Version in base suite: 1.62.0+dfsg-2 Base version: ublock-origin_1.62.0+dfsg-2 Target version: ublock-origin_1.67.0+dfsg-1~deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/u/ublock-origin/ublock-origin_1.62.0+dfsg-2.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/u/ublock-origin/ublock-origin_1.67.0+dfsg-1~deb13u1.dsc /srv/release.debian.org/tmp/loyMF0iGQH/ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/line-hor-dashed.png |binary /srv/release.debian.org/tmp/loyMF0iGQH/ublock-origin-1.67.0+dfsg/platform/mv3/extension/img/icon_128_off.png |binary /srv/release.debian.org/tmp/loyMF0iGQH/ublock-origin-1.67.0+dfsg/platform/mv3/extension/img/icon_16_off.png |binary /srv/release.debian.org/tmp/loyMF0iGQH/ublock-origin-1.67.0+dfsg/platform/mv3/extension/img/icon_32_off.png |binary /srv/release.debian.org/tmp/loyMF0iGQH/ublock-origin-1.67.0+dfsg/platform/mv3/extension/img/icon_512.png |binary /srv/release.debian.org/tmp/loyMF0iGQH/ublock-origin-1.67.0+dfsg/platform/mv3/extension/img/icon_64_off.png |binary /srv/release.debian.org/tmp/loyMF0iGQH/ublock-origin-1.67.0+dfsg/src/css/fonts/Inter/Inter-Regular.woff2 |binary /srv/release.debian.org/tmp/loyMF0iGQH/ublock-origin-1.67.0+dfsg/src/css/fonts/Inter/Inter-SemiBold.woff2 |binary /srv/release.debian.org/tmp/loyMF0iGQH/ublock-origin-1.67.0+dfsg/src/js/wasm/biditrie.wasm |binary ublock-origin-1.67.0+dfsg/.eslintrc.yml | 30 ublock-origin-1.67.0+dfsg/.github/workflows/RELEASE.HEAD.md | 7 ublock-origin-1.67.0+dfsg/.github/workflows/main.yml | 6 ublock-origin-1.67.0+dfsg/.gitignore | 1 ublock-origin-1.67.0+dfsg/.gitmodules | 6 ublock-origin-1.67.0+dfsg/.jshintrc | 22 ublock-origin-1.67.0+dfsg/CHANGELOG.md | 131 ublock-origin-1.67.0+dfsg/Makefile | 135 ublock-origin-1.67.0+dfsg/README.md | 30 ublock-origin-1.67.0+dfsg/RELEASE.HEAD.md | 12 ublock-origin-1.67.0+dfsg/assets/assets.dev.json | 89 ublock-origin-1.67.0+dfsg/assets/assets.json | 95 ublock-origin-1.67.0+dfsg/debian/changelog | 13 ublock-origin-1.67.0+dfsg/debian/control | 4 ublock-origin-1.67.0+dfsg/debian/copyright | 1 ublock-origin-1.67.0+dfsg/debian/patches/CVE-2025-4215.patch | 96 ublock-origin-1.67.0+dfsg/debian/patches/series | 1 ublock-origin-1.67.0+dfsg/debian/webext-ublock-origin-chromium.lintian-overrides | 1 ublock-origin-1.67.0+dfsg/dist/chromium/publish-beta.py | 190 ublock-origin-1.67.0+dfsg/dist/chromium/publish-stable.py | 190 ublock-origin-1.67.0+dfsg/dist/firefox/publish-signed-beta.py | 331 ublock-origin-1.67.0+dfsg/dist/firefox/updates.json | 24 ublock-origin-1.67.0+dfsg/dist/firefox/updates.template.json | 13 ublock-origin-1.67.0+dfsg/dist/mv3/chromium/publish-beta.py | 195 ublock-origin-1.67.0+dfsg/dist/mv3/firefox/publish-signed-beta.py | 326 ublock-origin-1.67.0+dfsg/dist/mv3/firefox/updates.json | 13 ublock-origin-1.67.0+dfsg/dist/mv3/firefox/updates.template.json | 13 ublock-origin-1.67.0+dfsg/dist/version | 2 ublock-origin-1.67.0+dfsg/eslint.config.mjs | 51 ublock-origin-1.67.0+dfsg/package-lock.json | 1163 ublock-origin-1.67.0+dfsg/package.json | 32 ublock-origin-1.67.0+dfsg/platform/browser/main.js | 123 ublock-origin-1.67.0+dfsg/platform/browser/test.html | 71 ublock-origin-1.67.0+dfsg/platform/chromium/is-webrtc-supported.html | 2 ublock-origin-1.67.0+dfsg/platform/chromium/is-webrtc-supported.js | 6 ublock-origin-1.67.0+dfsg/platform/chromium/manifest.json | 2 ublock-origin-1.67.0+dfsg/platform/chromium/vapi-background-ext.js | 9 ublock-origin-1.67.0+dfsg/platform/common/vapi-background.js | 55 ublock-origin-1.67.0+dfsg/platform/common/vapi-client.js | 2 ublock-origin-1.67.0+dfsg/platform/common/vapi-common.js | 9 ublock-origin-1.67.0+dfsg/platform/dig/snfe.js | 14 ublock-origin-1.67.0+dfsg/platform/firefox/manifest.json | 4 ublock-origin-1.67.0+dfsg/platform/firefox/vapi-background-ext.js | 8 ublock-origin-1.67.0+dfsg/platform/firefox/webext.js | 2 ublock-origin-1.67.0+dfsg/platform/mv3/README.md | 15 ublock-origin-1.67.0+dfsg/platform/mv3/chromium/manifest.json | 42 ublock-origin-1.67.0+dfsg/platform/mv3/description/en.md | 29 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ar.txt | 28 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.az.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.be.txt | 26 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.bg.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.bn.txt | 22 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.br_FR.txt | 24 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.bs.txt | 24 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ca.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.cs.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.cv.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.cy.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.da.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.de.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.el.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.en_GB.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.eo.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.es.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.et.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.eu.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.fa.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.fi.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.fil.txt | 22 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.fr.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.fy.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.gl.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.gu.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.he.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.hi.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.hr.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.hu.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.hy.txt | 24 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.id.txt | 24 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.it.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ja.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ka.txt | 24 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.kk.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.kn.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ko.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.lt.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.lv.txt | 24 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.mk.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ml.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.mr.txt | 30 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ms.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.nb.txt | 22 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.nl.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.oc.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.pa.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.pl.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.pt_BR.txt | 26 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.pt_PT.txt | 26 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ro.txt | 24 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ru.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.si.txt | 34 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.sk.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.sl.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.so.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.sq.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.sr.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.sv.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.sw.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ta.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.te.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.th.txt | 30 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.tr.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.uk.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ur.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.vi.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.zh_CN.txt | 26 ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.zh_TW.txt | 20 ublock-origin-1.67.0+dfsg/platform/mv3/edge/patch-extension.js | 71 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ar/messages.json | 186 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/az/messages.json | 156 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/be/messages.json | 154 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/bg/messages.json | 148 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/bn/messages.json | 208 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/br_FR/messages.json | 162 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/bs/messages.json | 212 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ca/messages.json | 150 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/cs/messages.json | 152 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/cv/messages.json | 158 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/cy/messages.json | 166 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/da/messages.json | 160 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/de/messages.json | 158 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/el/messages.json | 158 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/en/messages.json | 158 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/en_GB/messages.json | 152 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/eo/messages.json | 158 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/es/messages.json | 158 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/et/messages.json | 156 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/eu/messages.json | 172 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/fa/messages.json | 156 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/fi/messages.json | 162 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/fil/messages.json | 212 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/fr/messages.json | 158 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/fy/messages.json | 154 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/gl/messages.json | 156 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/gu/messages.json | 158 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/he/messages.json | 148 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/hi/messages.json | 178 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/hr/messages.json | 160 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/hu/messages.json | 152 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/hy/messages.json | 164 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/id/messages.json | 148 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/it/messages.json | 204 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ja/messages.json | 156 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ka/messages.json | 150 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/kk/messages.json | 158 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/kn/messages.json | 156 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ko/messages.json | 148 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/lt/messages.json | 158 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/lv/messages.json | 150 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/mk/messages.json | 148 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ml/messages.json | 156 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/mr/messages.json | 158 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ms/messages.json | 156 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/nb/messages.json | 212 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/nl/messages.json | 160 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/oc/messages.json | 158 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/pa/messages.json | 150 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/pl/messages.json | 150 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/pt_BR/messages.json | 206 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/pt_PT/messages.json | 164 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ro/messages.json | 208 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ru/messages.json | 160 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/si/messages.json | 196 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/sk/messages.json | 158 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/sl/messages.json | 158 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/so/messages.json | 158 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/sq/messages.json | 160 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/sr/messages.json | 152 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/sv/messages.json | 160 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/sw/messages.json | 158 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ta/messages.json | 158 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/te/messages.json | 158 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/th/messages.json | 256 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/tr/messages.json | 170 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/uk/messages.json | 152 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ur/messages.json | 156 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/vi/messages.json | 148 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/zh_CN/messages.json | 168 ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/zh_TW/messages.json | 150 ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/dashboard-common.css | 8 ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/dashboard.css | 37 ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/develop.css | 168 ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/filtering-mode.css | 50 ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/matched-rules.css | 3 ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/picker-ui.css | 144 ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/popup.css | 284 ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/report.css | 3 ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/settings.css | 159 ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/tool-overlay-ui.css | 99 ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/unpicker-ui.css | 64 ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/zapper-ui.css | 29 ublock-origin-1.67.0+dfsg/platform/mv3/extension/dashboard.html | 152 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/action.js | 110 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/admin.js | 126 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/background.js | 537 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/backup-restore.js | 153 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/config.js | 20 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/dashboard.js | 56 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/debug.js | 119 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/develop.js | 624 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/dnr-editor.js | 180 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/dnr-parser.js | 581 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/ext-compat.js | 103 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/ext.js | 52 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/fetch.js | 6 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/filter-lists.js | 57 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/filter-manager-ui.js | 486 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/filter-manager.js | 277 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/mode-editor.js | 91 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/mode-manager.js | 133 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/mode-parser.js | 211 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/picker-ui.js | 422 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/popup.js | 231 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/report.js | 48 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/ro-dnr-editor.js | 104 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/ruleset-manager.js | 634 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/rw-dnr-editor.js | 409 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting-manager.js | 337 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-api.js | 33 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-declarative.js | 157 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-generic.js | 68 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-procedural-api.js | 813 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-procedural.js | 852 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-specific.js | 100 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-user-terminate.js | 45 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-user.js | 48 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/isolated-api.js | 80 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/picker.js | 303 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/tool-overlay.js | 367 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/toolbar-icon.js | 27 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/unpicker.js | 57 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/zapper.js | 138 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/settings.js | 160 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/strictblock.js | 8 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/theme.js | 25 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/tool-overlay-ui.js | 237 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/troubleshooting.js | 130 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/ubo-parser.js | 581 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/unpicker-ui.js | 171 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/utils.js | 93 ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/zapper-ui.js | 133 ublock-origin-1.67.0+dfsg/platform/mv3/extension/lib/codemirror/README.md | 9 ublock-origin-1.67.0+dfsg/platform/mv3/extension/lib/codemirror/codemirror.LICENSE | 21 ublock-origin-1.67.0+dfsg/platform/mv3/extension/managed_storage.json | 27 ublock-origin-1.67.0+dfsg/platform/mv3/extension/matched-rules.html | 1 ublock-origin-1.67.0+dfsg/platform/mv3/extension/picker-ui.html | 56 ublock-origin-1.67.0+dfsg/platform/mv3/extension/popup.html | 45 ublock-origin-1.67.0+dfsg/platform/mv3/extension/report.html | 12 ublock-origin-1.67.0+dfsg/platform/mv3/extension/strictblock.html | 1 ublock-origin-1.67.0+dfsg/platform/mv3/extension/unpicker-ui.html | 40 ublock-origin-1.67.0+dfsg/platform/mv3/extension/zapper-ui.html | 32 ublock-origin-1.67.0+dfsg/platform/mv3/firefox/background.html | 10 ublock-origin-1.67.0+dfsg/platform/mv3/firefox/manifest.json | 38 ublock-origin-1.67.0+dfsg/platform/mv3/firefox/patch-ruleset.js | 30 ublock-origin-1.67.0+dfsg/platform/mv3/make-rulesets.js | 934 ublock-origin-1.67.0+dfsg/platform/mv3/make-scriptlets.js | 51 ublock-origin-1.67.0+dfsg/platform/mv3/rulesets.json | 636 ublock-origin-1.67.0+dfsg/platform/mv3/safari/css-api.js | 46 ublock-origin-1.67.0+dfsg/platform/mv3/safari/css-user.js | 59 ublock-origin-1.67.0+dfsg/platform/mv3/safari/ext-compat.js | 223 ublock-origin-1.67.0+dfsg/platform/mv3/safari/manifest.json | 89 ublock-origin-1.67.0+dfsg/platform/mv3/safari/patch-extension.js | 107 ublock-origin-1.67.0+dfsg/platform/mv3/safari/patch-ruleset.js | 69 ublock-origin-1.67.0+dfsg/platform/mv3/safe-replace.js | 4 ublock-origin-1.67.0+dfsg/platform/mv3/salvage-ruleids.mjs | 9 ublock-origin-1.67.0+dfsg/platform/mv3/scriptlets/css-declarative.template.js | 51 ublock-origin-1.67.0+dfsg/platform/mv3/scriptlets/css-generic.template.js | 72 ublock-origin-1.67.0+dfsg/platform/mv3/scriptlets/css-procedural.template.js | 15 ublock-origin-1.67.0+dfsg/platform/mv3/scriptlets/css-specific.template.js | 15 ublock-origin-1.67.0+dfsg/platform/mv3/scriptlets/scriptlet.template.js | 145 ublock-origin-1.67.0+dfsg/platform/nodejs/build.js | 5 ublock-origin-1.67.0+dfsg/platform/nodejs/index.js | 6 ublock-origin-1.67.0+dfsg/platform/npm/.eslintrc.json | 38 ublock-origin-1.67.0+dfsg/platform/npm/demo.js | 2 ublock-origin-1.67.0+dfsg/platform/npm/package-lock.json | 3043 ublock-origin-1.67.0+dfsg/platform/npm/package.json | 11 ublock-origin-1.67.0+dfsg/platform/npm/test.js | 7 ublock-origin-1.67.0+dfsg/platform/opera/manifest.json | 2 ublock-origin-1.67.0+dfsg/src/1p-filters.html | 1 ublock-origin-1.67.0+dfsg/src/3p-filters.html | 1 ublock-origin-1.67.0+dfsg/src/_locales/ar/messages.json | 126 ublock-origin-1.67.0+dfsg/src/_locales/az/messages.json | 16 ublock-origin-1.67.0+dfsg/src/_locales/be/messages.json | 48 ublock-origin-1.67.0+dfsg/src/_locales/bg/messages.json | 16 ublock-origin-1.67.0+dfsg/src/_locales/bn/messages.json | 22 ublock-origin-1.67.0+dfsg/src/_locales/br_FR/messages.json | 32 ublock-origin-1.67.0+dfsg/src/_locales/bs/messages.json | 36 ublock-origin-1.67.0+dfsg/src/_locales/ca/messages.json | 28 ublock-origin-1.67.0+dfsg/src/_locales/cs/messages.json | 18 ublock-origin-1.67.0+dfsg/src/_locales/cv/messages.json | 22 ublock-origin-1.67.0+dfsg/src/_locales/cy/messages.json | 66 ublock-origin-1.67.0+dfsg/src/_locales/da/messages.json | 22 ublock-origin-1.67.0+dfsg/src/_locales/de/messages.json | 30 ublock-origin-1.67.0+dfsg/src/_locales/el/messages.json | 46 ublock-origin-1.67.0+dfsg/src/_locales/en/messages.json | 22 ublock-origin-1.67.0+dfsg/src/_locales/en_GB/messages.json | 16 ublock-origin-1.67.0+dfsg/src/_locales/eo/messages.json | 18 ublock-origin-1.67.0+dfsg/src/_locales/es/messages.json | 24 ublock-origin-1.67.0+dfsg/src/_locales/et/messages.json | 22 ublock-origin-1.67.0+dfsg/src/_locales/eu/messages.json | 18 ublock-origin-1.67.0+dfsg/src/_locales/fa/messages.json | 16 ublock-origin-1.67.0+dfsg/src/_locales/fi/messages.json | 26 ublock-origin-1.67.0+dfsg/src/_locales/fil/messages.json | 30 ublock-origin-1.67.0+dfsg/src/_locales/fr/messages.json | 24 ublock-origin-1.67.0+dfsg/src/_locales/fy/messages.json | 26 ublock-origin-1.67.0+dfsg/src/_locales/gl/messages.json | 20 ublock-origin-1.67.0+dfsg/src/_locales/gu/messages.json | 22 ublock-origin-1.67.0+dfsg/src/_locales/he/messages.json | 18 ublock-origin-1.67.0+dfsg/src/_locales/hi/messages.json | 18 ublock-origin-1.67.0+dfsg/src/_locales/hr/messages.json | 26 ublock-origin-1.67.0+dfsg/src/_locales/hu/messages.json | 16 ublock-origin-1.67.0+dfsg/src/_locales/hy/messages.json | 18 ublock-origin-1.67.0+dfsg/src/_locales/id/messages.json | 22 ublock-origin-1.67.0+dfsg/src/_locales/it/messages.json | 20 ublock-origin-1.67.0+dfsg/src/_locales/ja/messages.json | 16 ublock-origin-1.67.0+dfsg/src/_locales/ka/messages.json | 32 ublock-origin-1.67.0+dfsg/src/_locales/kk/messages.json | 22 ublock-origin-1.67.0+dfsg/src/_locales/kn/messages.json | 34 ublock-origin-1.67.0+dfsg/src/_locales/ko/messages.json | 16 ublock-origin-1.67.0+dfsg/src/_locales/lt/messages.json | 18 ublock-origin-1.67.0+dfsg/src/_locales/lv/messages.json | 42 ublock-origin-1.67.0+dfsg/src/_locales/mk/messages.json | 16 ublock-origin-1.67.0+dfsg/src/_locales/ml/messages.json | 18 ublock-origin-1.67.0+dfsg/src/_locales/mr/messages.json | 22 ublock-origin-1.67.0+dfsg/src/_locales/ms/messages.json | 16 ublock-origin-1.67.0+dfsg/src/_locales/nb/messages.json | 28 ublock-origin-1.67.0+dfsg/src/_locales/nl/messages.json | 26 ublock-origin-1.67.0+dfsg/src/_locales/oc/messages.json | 22 ublock-origin-1.67.0+dfsg/src/_locales/pa/messages.json | 16 ublock-origin-1.67.0+dfsg/src/_locales/pl/messages.json | 18 ublock-origin-1.67.0+dfsg/src/_locales/pt_BR/messages.json | 140 ublock-origin-1.67.0+dfsg/src/_locales/pt_PT/messages.json | 52 ublock-origin-1.67.0+dfsg/src/_locales/ro/messages.json | 30 ublock-origin-1.67.0+dfsg/src/_locales/ru/messages.json | 22 ublock-origin-1.67.0+dfsg/src/_locales/si/messages.json | 304 ublock-origin-1.67.0+dfsg/src/_locales/sk/messages.json | 24 ublock-origin-1.67.0+dfsg/src/_locales/sl/messages.json | 16 ublock-origin-1.67.0+dfsg/src/_locales/so/messages.json | 22 ublock-origin-1.67.0+dfsg/src/_locales/sq/messages.json | 24 ublock-origin-1.67.0+dfsg/src/_locales/sr/messages.json | 16 ublock-origin-1.67.0+dfsg/src/_locales/sv/messages.json | 26 ublock-origin-1.67.0+dfsg/src/_locales/sw/messages.json | 16 ublock-origin-1.67.0+dfsg/src/_locales/ta/messages.json | 18 ublock-origin-1.67.0+dfsg/src/_locales/te/messages.json | 18 ublock-origin-1.67.0+dfsg/src/_locales/th/messages.json | 272 ublock-origin-1.67.0+dfsg/src/_locales/tr/messages.json | 26 ublock-origin-1.67.0+dfsg/src/_locales/uk/messages.json | 16 ublock-origin-1.67.0+dfsg/src/_locales/ur/messages.json | 22 ublock-origin-1.67.0+dfsg/src/_locales/vi/messages.json | 48 ublock-origin-1.67.0+dfsg/src/_locales/zh_CN/messages.json | 20 ublock-origin-1.67.0+dfsg/src/_locales/zh_TW/messages.json | 110 ublock-origin-1.67.0+dfsg/src/about.html | 1 ublock-origin-1.67.0+dfsg/src/advanced-settings.html | 3 ublock-origin-1.67.0+dfsg/src/asset-viewer.html | 3 ublock-origin-1.67.0+dfsg/src/blank.html | 11 ublock-origin-1.67.0+dfsg/src/code-viewer.html | 1 ublock-origin-1.67.0+dfsg/src/css/codemirror.css | 6 ublock-origin-1.67.0+dfsg/src/css/common.css | 11 ublock-origin-1.67.0+dfsg/src/css/dashboard.css | 2 ublock-origin-1.67.0+dfsg/src/css/document-blocked.css | 22 ublock-origin-1.67.0+dfsg/src/css/epicker-ui.css | 23 ublock-origin-1.67.0+dfsg/src/css/themes/default.css | 18 ublock-origin-1.67.0+dfsg/src/dashboard.html | 5 ublock-origin-1.67.0+dfsg/src/devtools.html | 3 ublock-origin-1.67.0+dfsg/src/document-blocked.html | 42 ublock-origin-1.67.0+dfsg/src/dyna-rules.html | 1 ublock-origin-1.67.0+dfsg/src/js/1p-filters.js | 7 ublock-origin-1.67.0+dfsg/src/js/3p-filters.js | 8 ublock-origin-1.67.0+dfsg/src/js/about.js | 2 ublock-origin-1.67.0+dfsg/src/js/advanced-settings.js | 4 ublock-origin-1.67.0+dfsg/src/js/arglist-parser.js | 4 ublock-origin-1.67.0+dfsg/src/js/asset-viewer.js | 6 ublock-origin-1.67.0+dfsg/src/js/assets.js | 34 ublock-origin-1.67.0+dfsg/src/js/background.js | 6 ublock-origin-1.67.0+dfsg/src/js/base64-custom.js | 2 ublock-origin-1.67.0+dfsg/src/js/benchmarks.js | 7 ublock-origin-1.67.0+dfsg/src/js/biditrie.js | 76 ublock-origin-1.67.0+dfsg/src/js/cachestorage.js | 14 ublock-origin-1.67.0+dfsg/src/js/click2load.js | 2 ublock-origin-1.67.0+dfsg/src/js/cloud-ui.js | 6 ublock-origin-1.67.0+dfsg/src/js/code-viewer.js | 45 ublock-origin-1.67.0+dfsg/src/js/codemirror/search-thread.js | 9 ublock-origin-1.67.0+dfsg/src/js/codemirror/search.js | 2 ublock-origin-1.67.0+dfsg/src/js/codemirror/ubo-dynamic-filtering.js | 4 ublock-origin-1.67.0+dfsg/src/js/codemirror/ubo-static-filtering.js | 7 ublock-origin-1.67.0+dfsg/src/js/commands.js | 6 ublock-origin-1.67.0+dfsg/src/js/console.js | 2 ublock-origin-1.67.0+dfsg/src/js/contentscript-extra.js | 3 ublock-origin-1.67.0+dfsg/src/js/contentscript.js | 10 ublock-origin-1.67.0+dfsg/src/js/contextmenu.js | 2 ublock-origin-1.67.0+dfsg/src/js/cosmetic-filtering.js | 129 ublock-origin-1.67.0+dfsg/src/js/dashboard-common.js | 2 ublock-origin-1.67.0+dfsg/src/js/dashboard.js | 4 ublock-origin-1.67.0+dfsg/src/js/devtools.js | 1 ublock-origin-1.67.0+dfsg/src/js/diff-updater.js | 21 ublock-origin-1.67.0+dfsg/src/js/document-blocked.js | 122 ublock-origin-1.67.0+dfsg/src/js/dom-inspector.js | 31 ublock-origin-1.67.0+dfsg/src/js/dom.js | 10 ublock-origin-1.67.0+dfsg/src/js/dyna-rules.js | 21 ublock-origin-1.67.0+dfsg/src/js/dynamic-net-filtering.js | 14 ublock-origin-1.67.0+dfsg/src/js/epicker-ui.js | 5 ublock-origin-1.67.0+dfsg/src/js/fa-icons.js | 2 ublock-origin-1.67.0+dfsg/src/js/filtering-engines.js | 4 ublock-origin-1.67.0+dfsg/src/js/hnswitches.js | 13 ublock-origin-1.67.0+dfsg/src/js/hntrie.js | 1 ublock-origin-1.67.0+dfsg/src/js/html-filtering.js | 91 ublock-origin-1.67.0+dfsg/src/js/httpheader-filtering.js | 80 ublock-origin-1.67.0+dfsg/src/js/i18n.js | 7 ublock-origin-1.67.0+dfsg/src/js/jsonpath.js | 524 ublock-origin-1.67.0+dfsg/src/js/logger-ui-inspector.js | 2 ublock-origin-1.67.0+dfsg/src/js/logger-ui.js | 26 ublock-origin-1.67.0+dfsg/src/js/logger.js | 4 ublock-origin-1.67.0+dfsg/src/js/lz4.js | 4 ublock-origin-1.67.0+dfsg/src/js/messaging.js | 20 ublock-origin-1.67.0+dfsg/src/js/mrucache.js | 2 ublock-origin-1.67.0+dfsg/src/js/pagestore.js | 31 ublock-origin-1.67.0+dfsg/src/js/popup-fenix.js | 113 ublock-origin-1.67.0+dfsg/src/js/redirect-engine.js | 8 ublock-origin-1.67.0+dfsg/src/js/redirect-resources.js | 1 ublock-origin-1.67.0+dfsg/src/js/regex-analyzer.js | 256 ublock-origin-1.67.0+dfsg/src/js/resources/attribute.js | 4 ublock-origin-1.67.0+dfsg/src/js/resources/cookie.js | 40 ublock-origin-1.67.0+dfsg/src/js/resources/create-html.js | 113 ublock-origin-1.67.0+dfsg/src/js/resources/href-sanitizer.js | 34 ublock-origin-1.67.0+dfsg/src/js/resources/json-edit.js | 1105 ublock-origin-1.67.0+dfsg/src/js/resources/json-prune.js | 275 ublock-origin-1.67.0+dfsg/src/js/resources/localstorage.js | 2 ublock-origin-1.67.0+dfsg/src/js/resources/noeval.js | 58 ublock-origin-1.67.0+dfsg/src/js/resources/object-prune.js | 272 ublock-origin-1.67.0+dfsg/src/js/resources/parse-replace.js | 8 ublock-origin-1.67.0+dfsg/src/js/resources/prevent-fetch.js | 221 ublock-origin-1.67.0+dfsg/src/js/resources/prevent-innerHTML.js | 82 ublock-origin-1.67.0+dfsg/src/js/resources/prevent-settimeout.js | 14 ublock-origin-1.67.0+dfsg/src/js/resources/proxy-apply.js | 6 ublock-origin-1.67.0+dfsg/src/js/resources/replace-argument.js | 29 ublock-origin-1.67.0+dfsg/src/js/resources/run-at.js | 2 ublock-origin-1.67.0+dfsg/src/js/resources/safe-self.js | 6 ublock-origin-1.67.0+dfsg/src/js/resources/scriptlets.js | 1269 ublock-origin-1.67.0+dfsg/src/js/resources/set-constant.js | 4 ublock-origin-1.67.0+dfsg/src/js/resources/shared.js | 18 ublock-origin-1.67.0+dfsg/src/js/resources/stack-trace.js | 148 ublock-origin-1.67.0+dfsg/src/js/resources/utils.js | 192 ublock-origin-1.67.0+dfsg/src/js/reverselookup-worker.js | 84 ublock-origin-1.67.0+dfsg/src/js/reverselookup.js | 29 ublock-origin-1.67.0+dfsg/src/js/s14e-serializer.js | 15 ublock-origin-1.67.0+dfsg/src/js/scriptlet-filtering-core.js | 153 ublock-origin-1.67.0+dfsg/src/js/scriptlet-filtering.js | 48 ublock-origin-1.67.0+dfsg/src/js/scriptlets/cosmetic-logger.js | 10 ublock-origin-1.67.0+dfsg/src/js/scriptlets/cosmetic-off.js | 2 ublock-origin-1.67.0+dfsg/src/js/scriptlets/cosmetic-on.js | 2 ublock-origin-1.67.0+dfsg/src/js/scriptlets/cosmetic-report.js | 10 ublock-origin-1.67.0+dfsg/src/js/scriptlets/dom-inspector.js | 6 ublock-origin-1.67.0+dfsg/src/js/scriptlets/dom-survey-elements.js | 2 ublock-origin-1.67.0+dfsg/src/js/scriptlets/dom-survey-scripts.js | 2 ublock-origin-1.67.0+dfsg/src/js/scriptlets/epicker.js | 10 ublock-origin-1.67.0+dfsg/src/js/scriptlets/load-3p-css.js | 4 ublock-origin-1.67.0+dfsg/src/js/scriptlets/load-large-media-all.js | 2 ublock-origin-1.67.0+dfsg/src/js/scriptlets/noscript-spoof.js | 50 ublock-origin-1.67.0+dfsg/src/js/scriptlets/scriptlet-loglevel-1.js | 2 ublock-origin-1.67.0+dfsg/src/js/scriptlets/scriptlet-loglevel-2.js | 2 ublock-origin-1.67.0+dfsg/src/js/scriptlets/should-inject-contentscript.js | 2 ublock-origin-1.67.0+dfsg/src/js/scriptlets/subscriber.js | 6 ublock-origin-1.67.0+dfsg/src/js/scriptlets/updater.js | 6 ublock-origin-1.67.0+dfsg/src/js/settings.js | 6 ublock-origin-1.67.0+dfsg/src/js/start.js | 47 ublock-origin-1.67.0+dfsg/src/js/static-dnr-filtering.js | 116 ublock-origin-1.67.0+dfsg/src/js/static-ext-filtering-db.js | 273 ublock-origin-1.67.0+dfsg/src/js/static-ext-filtering.js | 6 ublock-origin-1.67.0+dfsg/src/js/static-filtering-io.js | 2 ublock-origin-1.67.0+dfsg/src/js/static-filtering-parser.js | 475 ublock-origin-1.67.0+dfsg/src/js/static-net-filtering.js | 356 ublock-origin-1.67.0+dfsg/src/js/storage.js | 42 ublock-origin-1.67.0+dfsg/src/js/support.js | 6 ublock-origin-1.67.0+dfsg/src/js/tab.js | 50 ublock-origin-1.67.0+dfsg/src/js/tasks.js | 6 ublock-origin-1.67.0+dfsg/src/js/text-encode.js | 100 ublock-origin-1.67.0+dfsg/src/js/text-utils.js | 2 ublock-origin-1.67.0+dfsg/src/js/theme.js | 6 ublock-origin-1.67.0+dfsg/src/js/traffic.js | 177 ublock-origin-1.67.0+dfsg/src/js/ublock.js | 97 ublock-origin-1.67.0+dfsg/src/js/uri-utils.js | 20 ublock-origin-1.67.0+dfsg/src/js/url-net-filtering.js | 4 ublock-origin-1.67.0+dfsg/src/js/urlskip.js | 5 ublock-origin-1.67.0+dfsg/src/js/utils.js | 10 ublock-origin-1.67.0+dfsg/src/js/wasm/README.md | 2 ublock-origin-1.67.0+dfsg/src/js/wasm/biditrie.wat | 38 ublock-origin-1.67.0+dfsg/src/js/whitelist.js | 12 ublock-origin-1.67.0+dfsg/src/logger-ui.html | 3 ublock-origin-1.67.0+dfsg/src/no-dashboard.html | 1 ublock-origin-1.67.0+dfsg/src/popup-fenix.html | 3 ublock-origin-1.67.0+dfsg/src/settings.html | 1 ublock-origin-1.67.0+dfsg/src/support.html | 3 ublock-origin-1.67.0+dfsg/src/web_accessible_resources/epicker-ui.html | 2 ublock-origin-1.67.0+dfsg/src/web_accessible_resources/fingerprint2.js | 2 ublock-origin-1.67.0+dfsg/src/web_accessible_resources/google-ima.js | 21 ublock-origin-1.67.0+dfsg/src/whitelist.html | 1 ublock-origin-1.67.0+dfsg/tools/jsonpath-tool.html | 197 ublock-origin-1.67.0+dfsg/tools/make-mv3.sh | 209 ublock-origin-1.67.0+dfsg/tools/make-nodejs.sh | 64 ublock-origin-1.67.0+dfsg/tools/make-npm.sh | 1 ublock-origin-1.67.0+dfsg/uAssets/.github/ISSUE_TEMPLATE/bug_report.yml | 38 ublock-origin-1.67.0+dfsg/uAssets/.github/ISSUE_TEMPLATE/report_from_ubo.yml | 38 ublock-origin-1.67.0+dfsg/uAssets/.github/ISSUE_TEMPLATE/specific_report_from_ubo.yml | 36 ublock-origin-1.67.0+dfsg/uAssets/.github/ISSUE_TEMPLATE/specific_report_from_ubol.yml | 44 ublock-origin-1.67.0+dfsg/uAssets/.github/workflows/main.yml | 10 ublock-origin-1.67.0+dfsg/uAssets/.github/workflows/on-issue-created.yml | 54 ublock-origin-1.67.0+dfsg/uAssets/.github/workflows/on-youtube-issue.yml | 4 ublock-origin-1.67.0+dfsg/uAssets/.gitignore | 1 ublock-origin-1.67.0+dfsg/uAssets/filters/annoyances-cookies.txt | 2682 ublock-origin-1.67.0+dfsg/uAssets/filters/annoyances-others.txt | 858 ublock-origin-1.67.0+dfsg/uAssets/filters/badlists.txt | 5 ublock-origin-1.67.0+dfsg/uAssets/filters/badware.txt | 4177 ublock-origin-1.67.0+dfsg/uAssets/filters/experimental.txt | 36 ublock-origin-1.67.0+dfsg/uAssets/filters/filters-2020.txt | 814 ublock-origin-1.67.0+dfsg/uAssets/filters/filters-2021.txt | 1043 ublock-origin-1.67.0+dfsg/uAssets/filters/filters-2022.txt | 1466 ublock-origin-1.67.0+dfsg/uAssets/filters/filters-2023.txt | 1548 ublock-origin-1.67.0+dfsg/uAssets/filters/filters-2024.txt | 1334 ublock-origin-1.67.0+dfsg/uAssets/filters/filters-2025.txt | 2691 ublock-origin-1.67.0+dfsg/uAssets/filters/filters-general.txt | 2737 ublock-origin-1.67.0+dfsg/uAssets/filters/filters-mobile.txt | 45 ublock-origin-1.67.0+dfsg/uAssets/filters/filters.txt | 2411 ublock-origin-1.67.0+dfsg/uAssets/filters/lan-block.txt | 49 ublock-origin-1.67.0+dfsg/uAssets/filters/legacy.txt | 4 ublock-origin-1.67.0+dfsg/uAssets/filters/privacy.txt | 1136 ublock-origin-1.67.0+dfsg/uAssets/filters/quick-fixes.txt | 419 ublock-origin-1.67.0+dfsg/uAssets/filters/resource-abuse.txt | 39 ublock-origin-1.67.0+dfsg/uAssets/filters/ubo-link-shorteners.txt | 879 ublock-origin-1.67.0+dfsg/uAssets/filters/ubol-filters.txt | 320 ublock-origin-1.67.0+dfsg/uAssets/filters/unbreak.txt | 581 ublock-origin-1.67.0+dfsg/uAssets/templates/ublock-experimental.template | 8 ublock-origin-1.67.0+dfsg/uAssets/templates/ublock-filters.template | 2 ublock-origin-1.67.0+dfsg/uAssets/thirdparties/easylist/easylist-annoyances.txt | 446 ublock-origin-1.67.0+dfsg/uAssets/thirdparties/easylist/easylist-chat.txt | 37 ublock-origin-1.67.0+dfsg/uAssets/thirdparties/easylist/easylist-cookies.txt | 4416 ublock-origin-1.67.0+dfsg/uAssets/thirdparties/easylist/easylist-newsletters.txt | 755 ublock-origin-1.67.0+dfsg/uAssets/thirdparties/easylist/easylist-notifications.txt | 142 ublock-origin-1.67.0+dfsg/uAssets/thirdparties/easylist/easylist-social.txt | 772 ublock-origin-1.67.0+dfsg/uAssets/thirdparties/easylist/easylist.txt |53713 ++++++---- ublock-origin-1.67.0+dfsg/uAssets/thirdparties/easylist/easyprivacy.txt | 3185 ublock-origin-1.67.0+dfsg/uAssets/thirdparties/publicsuffix.org/list/effective_tld_names.dat | 670 ublock-origin-1.67.0+dfsg/uAssets/thirdparties/urlhaus-filter/urlhaus-filter-online.txt | 9075 + ublock-origin-1.67.0+dfsg/uAssets/tools/make-easylist.mjs | 13 ublock-origin-1.67.0+dfsg/uAssets/tools/make-ublock.sh | 3 564 files changed, 90737 insertions(+), 54010 deletions(-) diff -Nru ublock-origin-1.62.0+dfsg/.eslintrc.yml ublock-origin-1.67.0+dfsg/.eslintrc.yml --- ublock-origin-1.62.0+dfsg/.eslintrc.yml 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/.eslintrc.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -env: - browser: true - es2022: true -extends: eslint:recommended -parserOptions: - sourceType: module -rules: - eqeqeq: - - warn - - always - indent: - - error - - 4 - - ignoredNodes: - - Program > BlockStatement - - Program > ExpressionStatement > CallExpression > ArrowFunctionExpression > BlockStatement - - Program > ExpressionStatement > CallExpression > FunctionExpression > BlockStatement - - Program > IfStatement > BlockStatement - - Program > VariableDeclaration > VariableDeclarator > CallExpression > ArrowFunctionExpression > BlockStatement - - CallExpression > MemberExpression - - ArrayExpression > * - - ObjectExpression > * - no-control-regex: off - no-empty: off - sort-imports: warn - strict: warn -globals: - browser: readonly - chrome: readonly - vAPI: readonly diff -Nru ublock-origin-1.62.0+dfsg/.github/workflows/RELEASE.HEAD.md ublock-origin-1.67.0+dfsg/.github/workflows/RELEASE.HEAD.md --- ublock-origin-1.62.0+dfsg/.github/workflows/RELEASE.HEAD.md 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/.github/workflows/RELEASE.HEAD.md 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,7 @@ +[Commits to Master Since This Release](https://github.com/gorhill/uBlock/compare/%version%...master) + +#### How to Install the Developer Build: + +- **Firefox**: Signing pending + uBO works best on Gecko-based browsers, check out [why](https://github.com/gorhill/uBlock/wiki/uBlock-Origin-works-best-on-Firefox). +- **Chromium**: Install directly from the [Chrome Web Store](https://chromewebstore.google.com/detail/ublock-origin-development/cgbcahbpdhpcegmbfconppldiemgcoii). diff -Nru ublock-origin-1.62.0+dfsg/.github/workflows/main.yml ublock-origin-1.67.0+dfsg/.github/workflows/main.yml --- ublock-origin-1.62.0+dfsg/.github/workflows/main.yml 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/.github/workflows/main.yml 2025-10-25 19:32:51.000000000 +0000 @@ -29,13 +29,11 @@ run: | tools/make-chromium.sh ${{ env.VERSION }} tools/make-firefox.sh ${{ env.VERSION }} - tools/make-thunderbird.sh ${{ env.VERSION }} - tools/make-npm.sh ${{ env.VERSION }} - name: Assemble release notes run: | > release.body.txt grep -m1 -B10000 -- "----------" CHANGELOG.md >> release.body.txt - sed -e 's/%version%/${{ env.VERSION }}/g' RELEASE.HEAD.md >> release.body.txt + sed -e 's/%version%/${{ env.VERSION }}/g' .github/workflows/RELEASE.HEAD.md >> release.body.txt - name: Create GitHub release id: create_release uses: softprops/action-gh-release@v2 @@ -50,5 +48,3 @@ files: | dist/build/uBlock0_${{ env.VERSION }}.chromium.zip dist/build/uBlock0_${{ env.VERSION }}.firefox.xpi - dist/build/uBlock0_${{ env.VERSION }}.thunderbird.xpi - dist/build/uBlock0_${{ env.VERSION }}.npm.tgz diff -Nru ublock-origin-1.62.0+dfsg/.gitignore ublock-origin-1.67.0+dfsg/.gitignore --- ublock-origin-1.62.0+dfsg/.gitignore 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/.gitignore 2025-10-25 19:32:51.000000000 +0000 @@ -4,3 +4,4 @@ node_modules/ /dist/build/ /tmp/ +.DS_Store diff -Nru ublock-origin-1.62.0+dfsg/.gitmodules ublock-origin-1.67.0+dfsg/.gitmodules --- ublock-origin-1.62.0+dfsg/.gitmodules 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/.gitmodules 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,6 @@ +[submodule "platform/mv3/extension/lib/codemirror/codemirror-ubol"] + path = platform/mv3/extension/lib/codemirror/codemirror-ubol + url = https://github.com/gorhill/codemirror-ubol.git +[submodule "publish-extension"] + path = publish-extension + url = https://github.com/gorhill/publish-extension.git diff -Nru ublock-origin-1.62.0+dfsg/.jshintrc ublock-origin-1.67.0+dfsg/.jshintrc --- ublock-origin-1.62.0+dfsg/.jshintrc 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/.jshintrc 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -{ - "browser": true, - "devel": true, - "eqeqeq": true, - "esversion": 11, - "globals": { - "chrome": false, // global variable in Chromium, Chrome, Opera - "globalThis": false, - "self": false, - "vAPI": false, - "URLSearchParams": false, - "WebAssembly": false - }, - "laxbreak": true, - "newcap": false, - "nonew": false, - "strict": "global", - "sub": true, - "undef": true, - "unused": true, - "validthis": true -} diff -Nru ublock-origin-1.62.0+dfsg/CHANGELOG.md ublock-origin-1.67.0+dfsg/CHANGELOG.md --- ublock-origin-1.62.0+dfsg/CHANGELOG.md 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/CHANGELOG.md 2025-10-25 19:32:51.000000000 +0000 @@ -1,3 +1,134 @@ +- [Improve `href-sanitizer` scriptlet](https://github.com/gorhill/uBlock/commit/a43d1d8c42) +- [Fix `editInboundObjectFn` utility scriptlet](https://github.com/gorhill/uBlock/commit/d376adaae8) +- [Improve `trusted-replace-argument` scriptlet](https://github.com/gorhill/uBlock/commit/52bc354bce) +- [Add ability to test against regex in JSONPath expressions](https://github.com/gorhill/uBlock/commit/f36d2b8496) +- [Improve `proxy-apply` utility scriptlet](https://github.com/gorhill/uBlock/commit/dd4f764920) +- [Fix `removeparam` for multiple query parameters with same name](https://github.com/gorhill/uBlock/commit/3e5ea3b03f) +- [Improve `trusted-click-element` scriptlet](https://github.com/gorhill/uBlock/commit/9aa91ba111) +- [Improve `google-ima` shim](https://github.com/gorhill/uBlock/commit/8de47f250d) +- [Add back a uBO-specific version of "CERT.PL's Warning List"](https://github.com/gorhill/uBlock/commit/87dddb7d78) + +---------- + +# 1.66.4 + +- [Fix potential infinite loop when scanning for `$` anchor](https://github.com/gorhill/uBlock/commit/889c0eb208) +- [Allow generic exception for `replace=` option](https://github.com/gorhill/uBlock/commit/52dba4116e) + +---------- + +# 1.66.2 + +- [Fix version snafu](https://github.com/gorhill/uBlock/commit/50cb780107) + +---------- + +# 1.66.0 + +- [Improve `prevent-fetch` scriptlet](https://github.com/gorhill/uBlock/commit/d2bce26e7d) +- [Add support to strict-block from `ipaddress=` option](https://github.com/gorhill/uBlock/commit/6327aae56c) +- [Improve rendering with high-contrast theme](https://github.com/gorhill/uBlock/commit/5d7e5ee3a0) (fix suggested by @emv33) +- [Fix undue fetch from remote server at first install](https://github.com/gorhill/uBlock/commit/9327e19233) +- [Improve compatibility of `uritransform=` with DNR syntax](https://github.com/gorhill/uBlock/commit/aaf35d9d71) +- [Allow usage of `csp=`/`permissions=` with resource type object](https://github.com/gorhill/uBlock/commit/07e9f805bb) +- [JSONPath: Add ability to select root node for appending/modifying](https://github.com/gorhill/uBlock/commit/faff035203) +- [JSONPath: Add ability to substitute a pattern within a string value](https://github.com/gorhill/uBlock/commit/38ca6d41ff) +- [Remove "CERT.PL's Warning List" from stock lists](https://github.com/gorhill/uBlock/commit/e713e133eb) +- [Fix incorrect CNAME-related test in advanced settings](https://github.com/gorhill/uBlock/commit/171ddd3e06) +- [Remove "AdGuard Tracking Protection"from stock list](https://github.com/gorhill/uBlock/commit/14a9572c86) +- [Add filter list for experimental filters](https://github.com/gorhill/uBlock/commit/d88814bc12) +- [Improve `fingerprint2.js` shim](https://github.com/gorhill/uBlock/commit/7d9317bb17) +- [Make `google-ima` a valid injectable scriptlet](https://github.com/gorhill/uBlock/commit/47cbb43a0e) +- [Improve `abort-current-script` scriptlet](https://github.com/gorhill/uBlock/commit/fef50e59f2) +- [Fix potential exception in procedural operator `:matches-attr`](https://github.com/gorhill/uBlock/commit/e07e7bbd09) +- [Improve reporting of `reason` option in strict-blocked pages](https://github.com/gorhill/uBlock/commit/b7510eee61) +- [Improve `prevent-innerHTML` scriptlet](https://github.com/gorhill/uBlock/commit/b0396029bd) + +---------- + +# 1.65.0 + +## Fixes / changes + +- [Reset `important` option flag at `header` evaluation time](https://github.com/gorhill/uBlock/commit/66b68b4442) +- [Fix broken reverse lookup of filter lists](https://github.com/gorhill/uBlock/commit/527b4a201f) +- [Add `[trusted-]edit-inbound-object` scriptlets](https://github.com/gorhill/uBlock/commit/6e466cf945) +- [Improve `remove-cookie` scriptlet](https://github.com/gorhill/uBlock/commit/0a8ea58bb7) +- [Add `json-edit`-related scriptlets](https://github.com/gorhill/uBlock/commit/87e0434c90) +- [Improve `trusted-set-cookie` scriptlet](https://github.com/gorhill/uBlock/commit/3a2bb62519) +- [Force cache bypass reload when no-scripting switch is toggled](https://github.com/gorhill/uBlock/commit/4affe343dd) +- [Improve `jsonl[...]` suite of scriptlets](https://github.com/gorhill/uBlock/commit/ed9999efd6) +- [Add support for network filter option `message`](https://github.com/gorhill/uBlock/commit/d8298bb067) + - [Complete support for reporing strict-block messages](https://github.com/gorhill/uBlock/commit/253ef7ade3) +- [Make `header=` syntax compatible with DNR rules](https://github.com/gorhill/uBlock/commit/408b538e75) +- [Counter CodeMirror's `pointer-events: none` on scrollbars](https://github.com/gorhill/uBlock/commit/c44f043ed3) +- [Fix element picker issue with explicit dark theme](https://github.com/gorhill/uBlock/commit/0130fdf4a1) + +---------- + +# 1.64.0 + +## Fixes / changes + +- [Use custom blank page for embedded iframe in dashboard](https://github.com/gorhill/uBlock/commit/8cd6212867) +- [Use `color-scheme` `meta` tag, as suggested](https://github.com/gorhill/uBlock/commit/5c029b3532) +- [Bring zapper look in line with uBO Lite's zapper](https://github.com/gorhill/uBlock/commit/3f59f94b60) +- [Ignore `start_page` transition for popup-blocking purpose](https://github.com/gorhill/uBlock/commit/0243a141a7) +- [Exclude `chrome:` as valid openers for popup candidates](https://github.com/gorhill/uBlock/commit/59f4aca010) +- [Fetch diff patches from "reliable" servers only](https://github.com/gorhill/uBlock/commit/8b964a8c54) +- [Add `trusted-create-html` scriptlet](https://github.com/gorhill/uBlock/commit/20dd606504) +- [Mind potential race condition when dynamically registering scriptlets](https://github.com/gorhill/uBlock/commit/15e832da8a) +- [Fix undue unchecking of setting in "My filters"](https://github.com/gorhill/uBlock/commit/2bb6999e3f) +- [Add path support as target option in static extended filtering](https://github.com/gorhill/uBlock/commit/8b696a691a) +- [Add `trusted-prevent-fetch` scriptlet](https://github.com/gorhill/uBlock/commit/4ce26b63ff) +- [Code viewer shouldn't be maximizable](https://github.com/gorhill/uBlock/commit/97e740bd2c) +- [Add `json-edit` suite of scriptlets; extend `replace=` option](https://github.com/gorhill/uBlock/commit/b18daa53aa) +- [Improve `trusted-prevent-dom-bypass` scriptlet](https://github.com/gorhill/uBlock/commit/68a256bdde) +- [Add `jsonl-prune-xhr-response`/`jsonl-prune-fetch-response` scriptlets](https://github.com/gorhill/uBlock/commit/95a3be9d56) +- [Improve `[json-prune|trusted-replace]-fetch-response` scriptlets](https://github.com/gorhill/uBlock/commit/88fa550a96) + +---------- + +# 1.63.2 + +## Fixes / changes + +- [Fix TypedArray overflow](https://github.com/gorhill/uBlock/commit/76b80baaea) +- [Add prevent-innerHTML scriptlet](https://github.com/gorhill/uBlock/commit/fe744816f1) + +---------- + +# 1.63.0 + +## Fixes / changes + +- [Improve `prevent-set[Timeout|Interval]` scriptlets](https://github.com/gorhill/uBlock/commit/d36ea89a02) +- [Add quit button to element zapper mode](https://github.com/gorhill/uBlock/commit/4aebdbb0a9) +- [Improve `trusted-override-element-method` scriptlet](https://github.com/gorhill/uBlock/commit/9e946ce0c3) +- [Disable obsolete cache-control workaround for Firefox](https://github.com/gorhill/uBlock/commit/34cea70924) +- [Improve `overlay-buster` scriptlet](https://github.com/gorhill/uBlock/commit/fc231998b9) +- [Add ability to inject scriptlets according to origin of ancestor contexts](https://github.com/gorhill/uBlock/commit/a483f7955f) +- [Fix range parser in prevent-setTimeout scriptlet](https://github.com/gorhill/uBlock/commit/e636c32f2a) +- [Add filter option synonyms for `strict1p`/`strict3p`](https://github.com/gorhill/uBlock/commit/34df044808) +- [Increase URL buffer size to 8192 (from 2048)](https://github.com/gorhill/uBlock/commit/36404543e4) +- [Use onmessage/postMessage instead of BroadcastChannel in diff updater](https://github.com/gorhill/uBlock/commit/ea8853cda3) +- [Improve `disable-newtab-links` scriptlet](https://github.com/gorhill/uBlock/commit/d41989e62a) +- [Improve `prevent-addEventListener` scriptlet](https://github.com/gorhill/uBlock/commit/9c26a07b53) +- [Fix reverse lookup of `##^responseheader(...)` filters](https://github.com/gorhill/uBlock/commit/5921e50e03) +- [Improve `evaldata-prune` scriptlet](https://github.com/gorhill/uBlock/commit/9bb1a2baaf) +- [Comply with Mozilla's "User Consent and Control"](https://github.com/gorhill/uBlock/commit/344539d793) +- [Improve `noeval-if` scriptlet](https://github.com/gorhill/uBlock/commit/0df7faffac) +- [Add "closed","next", "mandatory", "agree/disagree" values to `set-cookie` scriptlet](https://github.com/gorhill/uBlock/commit/35a47d674b) (by @ryanbr) +- [Add `decline` value to `set-cookie` scriptlet](https://github.com/gorhill/uBlock/commit/4b12247da1) +- [Improve `abort-on-stack-trace` scriptlet](https://github.com/gorhill/uBlock/commit/b617926c1c) +- [Improve `href-sanitizer` scriptlet](https://github.com/gorhill/uBlock/commit/551c6bc6eb) + +---------- + +# 1.62.0 + +## Fixes / changes + - [Fix deserialization of ArrayBuffer shared by multiple TypedArrays](https://github.com/gorhill/uBlock/commit/c92a518218) - [Improve `trusted-suppress-native-method` scriptlet](https://github.com/gorhill/uBlock/commit/cb6c11ab6f) - [Improve `urlskip=` filter option](https://github.com/gorhill/uBlock/commit/a7aa755f18) diff -Nru ublock-origin-1.62.0+dfsg/Makefile ublock-origin-1.67.0+dfsg/Makefile --- ublock-origin-1.62.0+dfsg/Makefile 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/Makefile 2025-10-25 19:32:51.000000000 +0000 @@ -2,12 +2,24 @@ run_options := $(filter-out $@,$(MAKECMDGOALS)) .PHONY: all clean cleanassets test lint chromium opera firefox npm dig \ - mv3 mv3-quick mv3-chromium mv3-firefox \ - compare maxcost medcost mincost modifiers record wasm + mv3-chromium mv3-firefox mv3-edge mv3-safari ubol-codemirror \ + compare maxcost medcost mincost modifiers record wasm \ + publish-chromium publish-edge publish-firefox \ + publish-dev-chromium publish-dev-firefox \ + upload-firefox upload-dev-firefox -sources := $(wildcard assets/* assets/*/* dist/version src/* src/*/* src/*/*/* src/*/*/*/*) -platform := $(wildcard platform/* platform/*/* platform/*/*/* platform/*/*/*/* platform/*/*/*/*/*) +sources := ./dist/version $(shell find ./assets -type f) $(shell find ./src -type f) +platform := $(wildcard platform/*/*) assets := dist/build/uAssets +mv3-sources := \ + $(shell find ./src -type f) \ + $(wildcard platform/mv3/*) \ + $(shell find ./platform/mv3/extension -name codemirror-ubol -prune -o -type f) \ + platform/mv3/extension/lib/codemirror/codemirror-ubol/dist/cm6.bundle.ubol.min.js +mv3-data := $(shell find ./dist/build/mv3-data -type f) + +mv3-edge-deps := $(wildcard platform/mv3/edge/*) +mv3-safari-deps := $(wildcard platform/mv3/safari/*) all: chromium firefox npm @@ -32,20 +44,16 @@ dist/build/uBlock0.npm: tools/make-nodejs.sh $(sources) $(platform) $(assets) tools/make-npm.sh -# Build the Node.js package. npm: dist/build/uBlock0.npm -lint: npm - cd dist/build/uBlock0.npm && npm run lint - -test: npm - cd dist/build/uBlock0.npm && npm run test +# Dev tools +node_modules: + npm install -test-full-battery: npm - cd dist/build/uBlock0.npm && npm run test-full-battery +init: node_modules -check-leaks: npm - cd dist/build/uBlock0.npm && npm run check-leaks +lint: init + npm run lint dist/build/uBlock0.dig: tools/make-nodejs.sh $(sources) $(platform) $(assets) tools/make-dig.sh @@ -56,31 +64,112 @@ dig-snfe: dig cd dist/build/uBlock0.dig && npm run snfe $(run_options) -dist/build/uBOLite.chromium: tools/make-mv3.sh $(sources) $(platform) +dist/build/mv3-data: + mkdir -p dist/build/mv3-data + +ubol-codemirror: + $(MAKE) -sC platform/mv3/extension/lib/codemirror/codemirror-ubol/ ubol.bundle + +dist/build/uBOLite.chromium: tools/make-mv3.sh $(mv3-sources) $(platform) $(mv3-data) dist/build/mv3-data tools/make-mv3.sh chromium -mv3-chromium: dist/build/uBOLite.chromium +mv3-chromium: ubol-codemirror dist/build/uBOLite.chromium -dist/build/uBOLite.firefox: tools/make-mv3.sh $(sources) $(platform) +dist/build/uBOLite.firefox: tools/make-mv3.sh $(mv3-sources) $(platform) $(mv3-data) dist/build/mv3-data tools/make-mv3.sh firefox -mv3-firefox: dist/build/uBOLite.firefox +mv3-firefox: ubol-codemirror dist/build/uBOLite.firefox -mv3-quick: tools/make-mv3.sh $(sources) $(platform) - tools/make-mv3.sh quick +dist/build/uBOLite.edge: tools/make-mv3.sh $(mv3-sources) $(mv3-edge-deps) $(mv3-data) dist/build/mv3-data + tools/make-mv3.sh edge -mv3-full: tools/make-mv3.sh $(sources) $(platform) - tools/make-mv3.sh full +mv3-edge: ubol-codemirror dist/build/uBOLite.edge + +dist/build/uBOLite.safari: tools/make-mv3.sh $(mv3-sources) $(mv3-safari-deps) $(mv3-data) dist/build/mv3-data + tools/make-mv3.sh safari + +mv3-safari: ubol-codemirror dist/build/uBOLite.safari dist/build/uAssets: tools/pull-assets.sh clean: - rm -rf dist/build tmp/node_modules + rm -rf dist/build tmp/node_modules node_modules cleanassets: rm -rf dist/build/mv3-data dist/build/uAssets +# Usage: make publish-publish version=? +publish-chromium: + node publish-extension/publish-chromium.js \ + ghowner=gorhill \ + ghrepo=uBlock \ + ghtag=$(version) \ + ghasset=chromium \ + storeid=cjpalhdlnbpafiamejdnhcphjbkeiagm + +# Usage: make publish-edge version=? +publish-edge: + node publish-extension/publish-edge.js \ + ghowner=gorhill \ + ghrepo=uBlock \ + ghtag=$(version) \ + ghasset=chromium \ + datebasedmajor=1 \ + storeid=odfafepnkmbhccpbejgmiehpchacaeak \ + productid=$(shell secret-tool lookup token ubo_edge_id) + +# Usage: make publish-firefox version=? +publish-firefox: + node publish-extension/publish-firefox.js \ + ghowner=gorhill \ + ghrepo=uBlock \ + ghtag=$(version) \ + ghasset=firefox \ + storeid=uBlock0@raymondhill.net \ + channel=listed + +# Usage: make publish-dev-chromium version=? +publish-dev-chromium: + node publish-extension/publish-chromium.js \ + ghowner=gorhill \ + ghrepo=uBlock \ + ghtag=$(version) \ + ghasset=chromium \ + storeid=cgbcahbpdhpcegmbfconppldiemgcoii + +# Usage: make publish-dev-firefox version=? +publish-dev-firefox: + node publish-extension/publish-firefox.js \ + ghowner=gorhill \ + ghrepo=uBlock \ + ghtag=$(version) \ + ghasset=firefox \ + storeid=uBlock0@raymondhill.net \ + channel=unlisted \ + updatepath=./dist/firefox/updates.json + +# Usage: make upload-firefox version=? +upload-firefox: + node publish-extension/upload-firefox.js \ + ghowner=gorhill \ + ghrepo=uBlock \ + ghtag=$(version) \ + ghasset=firefox \ + storeid=uBlock0@raymondhill.net \ + channel=listed + +# Usage: make upload-dev-firefox version=? +upload-dev-firefox: + node publish-extension/upload-firefox.js \ + ghowner=gorhill \ + ghrepo=uBlock \ + ghtag=$(version) \ + ghasset=firefox \ + storeid=uBlock0@raymondhill.net \ + channel=unlisted \ + updatepath=./dist/firefox/updates.json + # Not real targets, just convenient for auto-completion at shell prompt compare: @echo diff -Nru ublock-origin-1.62.0+dfsg/README.md ublock-origin-1.67.0+dfsg/README.md --- ublock-origin-1.62.0+dfsg/README.md 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/README.md 2025-10-25 19:32:51.000000000 +0000 @@ -15,25 +15,15 @@ uBlock Origin (uBO) -

-BEWARE! uBO is (and has always been) COMPLETELY UNRELATED to the website ublock.org. -

-*** - -

-Get uBlock Origin for Firefox -Get uBlock Origin for Microsoft Edge -Get uBlock Origin for Opera -Get uBlock Origin for Thunderbird -

- -*** - -

-Get uBlock Origin for Chromium
-IMPORTANT: About Google Chrome's "This extension may soon no longer be supported" -

+| Browser | Install from ... | Status | +| :-------: | ---------------- | ------ | +| Get uBlock Origin for Firefox | Firefox Add-ons | [uBO works best on Firefox](https://github.com/gorhill/uBlock/wiki/uBlock-Origin-works-best-on-Firefox) | +| Get uBlock Origin for Microsoft Edge | Edge Add-ons | +| Get uBlock Origin for Opera | Opera Add-ons | +| Get uBlock Origin for Chromium | Chrome Web Store | About Google Chrome's "This extension may soon no longer be supported"
End of support on Chrome 139 | +| Get uBlock Origin for Thunderbird | Thunderbird Add-ons | [No longer updated and stuck at 1.49.2.](https://github.com/uBlockOrigin/uBlock-issues/issues/2928) Later versions require "GitHub - Releases". | +| Get uBlock Origin through GitHub | GitHub - Releases | Stable and development versions on Firefox, Chromium MV2, and Thunderbird. Must be placed manually into web browsers; the Chromium and Thunderbird versions usually won't auto-update. *** @@ -105,7 +95,7 @@ [Chrome Web Store][Chrome] -[Microsoft Edge Add-ons][Edge] (Published by: [Nicole Rolls][Nicole Rolls]) +[Microsoft Edge Add-ons][Edge] (Published by [Nicole Rolls][Nicole Rolls] until version 1.62. Ownership transfer at version 1.64.) [Opera Add-ons][Opera] @@ -148,7 +138,7 @@ [Peter Lowe's Blocklist]: https://pgl.yoyo.org/adservers/ [Malicious Blocklist]: https://gitlab.com/malware-filter/urlhaus-filter#malicious-url-blocklist -[Performance]: https://www.debugbear.com/blog/chrome-extension-performance-2021#how-do-ad-blockers-and-privacy-tools-affect-browser-performance +[Performance]: https://www.debugbear.com/blog/chrome-extensions-website-performance#the-impact-of-ad-blocking-on-website-performance [EasyPrivacy]: https://easylist.to/#easyprivacy [Thunderbird]: https://addons.thunderbird.net/thunderbird/addon/ublock-origin/ [Chrome Dev]: https://chromewebstore.google.com/detail/ublock-origin-development/cgbcahbpdhpcegmbfconppldiemgcoii diff -Nru ublock-origin-1.62.0+dfsg/RELEASE.HEAD.md ublock-origin-1.67.0+dfsg/RELEASE.HEAD.md --- ublock-origin-1.62.0+dfsg/RELEASE.HEAD.md 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/RELEASE.HEAD.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -[Commits to Master Since This Release](https://github.com/gorhill/uBlock/compare/%version%...master) - -#### How to Install the Developer Build: - -- **Firefox**: Download the build from [uBlock0_%version%.firefox.signed.xpi](https://github.com/gorhill/uBlock/releases/download/%version%/uBlock0_%version%.firefox.signed.xpi). - - uBO works best on Firefox, check out [why](https://github.com/gorhill/uBlock/wiki/uBlock-Origin-works-best-on-Firefox). - -- **Chromium**: Install directly from the [Chrome Web Store](https://chromewebstore.google.com/detail/ublock-origin-development/cgbcahbpdhpcegmbfconppldiemgcoii). - -- **Thunderbird**: Download [uBlock0_%version%.thunderbird.xpi](https://github.com/gorhill/uBlock/releases/download/%version%/uBlock0_%version%.thunderbird.xpi) and drag it into Thunderbird's _Add-ons Manager_ (requires Thunderbird 91+). - -- **Node.js**: You can import from [npm](https://www.npmjs.com/package/@gorhill/ubo-core) or download and unzip [uBlock0_%version%.npm.tgz](https://github.com/gorhill/uBlock/releases/download/%version%/uBlock0_%version%.npm.tgz). diff -Nru ublock-origin-1.62.0+dfsg/assets/assets.dev.json ublock-origin-1.67.0+dfsg/assets/assets.dev.json --- ublock-origin-1.62.0+dfsg/assets/assets.dev.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/assets/assets.dev.json 2025-10-25 19:32:51.000000000 +0000 @@ -52,6 +52,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/filters.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/filters.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "ublock-badware": { @@ -71,6 +75,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/badware.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/badware.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets", "instructionURL": "https://github.com/gorhill/uBlock/wiki/Badware-risks" }, @@ -91,6 +99,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/privacy.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/privacy.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "ublock-unbreak": { @@ -109,6 +121,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/unbreak.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/unbreak.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "ublock-quick-fixes": { @@ -127,6 +143,28 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/quick-fixes.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/quick-fixes.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], + "supportURL": "https://github.com/uBlockOrigin/uAssets" + }, + "ublock-experimental": { + "content": "filters", + "group": "default", + "off": true, + "title": "uBlock filters – Experimental", + "contentURL": "https://ublockorigin.github.io/uAssets/filters/experimental.txt", + "cdnURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/experimental.min.txt", + "https://ublockorigin.pages.dev/filters/experimental.min.txt", + "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/experimental.min.txt", + "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/experimental.min.txt" + ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "adguard-generic": { @@ -163,6 +201,10 @@ "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/thirdparties/easylist.txt", "https://ublockorigin.pages.dev/thirdparties/easylist.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://easylist.to/" }, "adguard-spyware-url": { @@ -174,14 +216,6 @@ "contentURL": "https://filters.adtidy.org/extension/ublock/filters/17.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, - "adguard-spyware": { - "content": "filters", - "group": "privacy", - "off": true, - "title": "AdGuard Tracking Protection", - "contentURL": "https://filters.adtidy.org/extension/ublock/filters/3.txt", - "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" - }, "block-lan": { "content": "filters", "group": "privacy", @@ -212,6 +246,10 @@ "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/thirdparties/easyprivacy.txt", "https://ublockorigin.pages.dev/thirdparties/easyprivacy.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://easylist.to/" }, "urlhaus-1": { @@ -478,6 +516,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/annoyances.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/annoyances.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "dpollock-0": { @@ -520,7 +562,7 @@ "off": true, "title": "🇪🇬eg 🇸🇦sa 🇲🇦ma 🇩🇿dz: Liste AR", "tags": "ads arabic اَلْعَرَبِيَّةُ‎", - "lang": "ar", + "lang": "ar kab", "contentURL": "https://easylist-downloads.adblockplus.org/Liste_AR.txt", "supportURL": "https://forums.lanik.us/viewforum.php?f=98" }, @@ -593,7 +635,7 @@ "off": true, "title": "🇫🇷fr 🇨🇦ca: AdGuard Français", "tags": "ads french", - "lang": "ar br ff fr lb oc son", + "lang": "ar br ff fr kab lb oc son", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/16.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, @@ -647,7 +689,7 @@ "off": true, "title": "🇮🇳in 🇱🇰lk 🇳🇵np: IndianList", "tags": "ads assamese bengali gujarati hindi kannada malayalam marathi nepali punjabi sinhala tamil telugu", - "lang": "as bn gu hi kn ml mr ne pa si ta te", + "lang": "as bn gu hi kn ml mr ne pa sat si ta te", "contentURL": "https://easylist-downloads.adblockplus.org/indianlist.txt", "supportURL": "https://github.com/mediumkreation/IndianList" }, @@ -694,7 +736,7 @@ "off": true, "title": "🇮🇹it: EasyList Italy", "tags": "ads italian", - "lang": "it lij", + "lang": "fur it lij sc", "contentURL": "https://easylist-downloads.adblockplus.org/easylistitaly.txt", "supportURL": "https://forums.lanik.us/viewforum.php?f=96" }, @@ -784,21 +826,20 @@ "off": true, "title": "🇵🇱pl: Oficjalne Polskie Filtry do uBlocka Origin", "tags": "ads polish polski", - "lang": "szl pl", + "lang": "szl pl _", "contentURL": "https://raw.githubusercontent.com/MajkiIT/polish-ads-filter/master/polish-adblock-filters/adblock.txt", - "supportURL": "https://github.com/MajkiIT/polish-ads-filter/issues", - "instructionURL": "https://github.com/MajkiIT/polish-ads-filter#polish-filters-for-adblock-ublock-origin--adguard" + "supportURL": "https://github.com/MajkiIT/polish-ads-filter" }, - "POL-2": { + "POL-3": { "content": "filters", "group": "regions", "parent": "🇵🇱pl: Oficjalne Polskie Filtry", "off": true, - "title": "🇵🇱pl: Oficjalne polskie filtry przeciwko alertom o Adblocku", - "tags": "ads polish polski", + "title": "🇵🇱pl: CERT.PL's Warning List", + "tags": "malware polish polski", "lang": "szl pl", - "contentURL": "https://raw.githubusercontent.com/olegwukr/polish-privacy-filters/master/anti-adblock.txt", - "supportURL": "https://github.com/olegwukr/polish-privacy-filters/issues" + "contentURL": "https://hole.cert.pl/domains/v2/domains_ublock.txt", + "supportURL": "https://cert.pl/lista-ostrzezen/" }, "ROU-1": { "content": "filters", @@ -818,7 +859,7 @@ "parent": "🇷🇺ru 🇺🇦ua 🇺🇿uz 🇰🇿kz: RU AdList", "off": true, "title": "🇷🇺ru 🇺🇦ua 🇺🇿uz 🇰🇿kz: RU AdList", - "tags": "ads belarusian беларуская kazakh tatar russian русский ukrainian українська uzbek", + "tags": "ads belarusian беларуская kazakh tatar russian русский ukrainian українська uzbek uk", "lang": "be kk tt ru uz", "contentURL": "https://raw.githubusercontent.com/easylist/ruadlist/master/RuAdList-uBO.txt", "cdnURLs": [ @@ -913,11 +954,11 @@ "content": "filters", "group": "regions", "off": true, - "title": "🇺🇦ua: Ukrainian Filters", + "title": "🇺🇦ua: AdGuard Ukrainian", "tags": "ads ukraine україна", "lang": "uk", - "contentURL": "https://raw.githubusercontent.com/ukrainianfilters/lists/main/combined/uBO/uBO.txt", - "supportURL": "https://github.com/ukrainianfilters/lists" + "contentURL": "https://filters.adtidy.org/extension/ublock/filters/23.txt", + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "VIE-1": { "content": "filters", diff -Nru ublock-origin-1.62.0+dfsg/assets/assets.json ublock-origin-1.67.0+dfsg/assets/assets.json --- ublock-origin-1.62.0+dfsg/assets/assets.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/assets/assets.json 2025-10-25 19:32:51.000000000 +0000 @@ -52,6 +52,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/filters.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/filters.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "ublock-badware": { @@ -71,6 +75,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/badware.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/badware.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets", "instructionURL": "https://github.com/gorhill/uBlock/wiki/Badware-risks" }, @@ -91,6 +99,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/privacy.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/privacy.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "ublock-unbreak": { @@ -109,6 +121,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/unbreak.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/unbreak.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "ublock-quick-fixes": { @@ -127,6 +143,28 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/quick-fixes.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/quick-fixes.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], + "supportURL": "https://github.com/uBlockOrigin/uAssets" + }, + "ublock-experimental": { + "content": "filters", + "group": "default", + "off": true, + "title": "uBlock filters – Experimental", + "contentURL": "https://ublockorigin.github.io/uAssets/filters/experimental.txt", + "cdnURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/experimental.min.txt", + "https://ublockorigin.pages.dev/filters/experimental.min.txt", + "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/experimental.min.txt", + "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/experimental.min.txt" + ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "adguard-generic": { @@ -163,6 +201,10 @@ "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/thirdparties/easylist.txt", "https://ublockorigin.pages.dev/thirdparties/easylist.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://easylist.to/" }, "adguard-spyware-url": { @@ -174,14 +216,6 @@ "contentURL": "https://filters.adtidy.org/extension/ublock/filters/17.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, - "adguard-spyware": { - "content": "filters", - "group": "privacy", - "off": true, - "title": "AdGuard Tracking Protection", - "contentURL": "https://filters.adtidy.org/extension/ublock/filters/3.txt", - "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" - }, "block-lan": { "content": "filters", "group": "privacy", @@ -212,6 +246,10 @@ "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/thirdparties/easyprivacy.txt", "https://ublockorigin.pages.dev/thirdparties/easyprivacy.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://easylist.to/" }, "urlhaus-1": { @@ -478,6 +516,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/annoyances.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/annoyances.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "dpollock-0": { @@ -520,7 +562,7 @@ "off": true, "title": "🇪🇬eg 🇸🇦sa 🇲🇦ma 🇩🇿dz: Liste AR", "tags": "ads arabic اَلْعَرَبِيَّةُ‎", - "lang": "ar", + "lang": "ar kab", "contentURL": "https://easylist-downloads.adblockplus.org/Liste_AR.txt", "supportURL": "https://forums.lanik.us/viewforum.php?f=98" }, @@ -593,7 +635,7 @@ "off": true, "title": "🇫🇷fr 🇨🇦ca: AdGuard Français", "tags": "ads french", - "lang": "ar br ff fr lb oc son", + "lang": "ar br ff fr kab lb oc son", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/16.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, @@ -647,7 +689,7 @@ "off": true, "title": "🇮🇳in 🇱🇰lk 🇳🇵np: IndianList", "tags": "ads assamese bengali gujarati hindi kannada malayalam marathi nepali punjabi sinhala tamil telugu", - "lang": "as bn gu hi kn ml mr ne pa si ta te", + "lang": "as bn gu hi kn ml mr ne pa sat si ta te", "contentURL": "https://easylist-downloads.adblockplus.org/indianlist.txt", "supportURL": "https://github.com/mediumkreation/IndianList" }, @@ -694,7 +736,7 @@ "off": true, "title": "🇮🇹it: EasyList Italy", "tags": "ads italian", - "lang": "it lij", + "lang": "fur it lij sc", "contentURL": "https://easylist-downloads.adblockplus.org/easylistitaly.txt", "supportURL": "https://forums.lanik.us/viewforum.php?f=96" }, @@ -784,21 +826,20 @@ "off": true, "title": "🇵🇱pl: Oficjalne Polskie Filtry do uBlocka Origin", "tags": "ads polish polski", - "lang": "szl pl", + "lang": "szl pl _", "contentURL": "https://raw.githubusercontent.com/MajkiIT/polish-ads-filter/master/polish-adblock-filters/adblock.txt", - "supportURL": "https://github.com/MajkiIT/polish-ads-filter/issues", - "instructionURL": "https://github.com/MajkiIT/polish-ads-filter#polish-filters-for-adblock-ublock-origin--adguard" + "supportURL": "https://github.com/MajkiIT/polish-ads-filter" }, - "POL-2": { + "POL-3": { "content": "filters", "group": "regions", "parent": "🇵🇱pl: Oficjalne Polskie Filtry", "off": true, - "title": "🇵🇱pl: Oficjalne polskie filtry przeciwko alertom o Adblocku", - "tags": "ads polish polski", + "title": "🇵🇱pl: CERT.PL's Warning List", + "tags": "malware polish polski", "lang": "szl pl", - "contentURL": "https://raw.githubusercontent.com/olegwukr/polish-privacy-filters/master/anti-adblock.txt", - "supportURL": "https://github.com/olegwukr/polish-privacy-filters/issues" + "contentURL": "https://hole.cert.pl/domains/v2/domains_ublock.txt", + "supportURL": "https://cert.pl/lista-ostrzezen/" }, "ROU-1": { "content": "filters", @@ -818,8 +859,8 @@ "parent": "🇷🇺ru 🇺🇦ua 🇺🇿uz 🇰🇿kz: RU AdList", "off": true, "title": "🇷🇺ru 🇺🇦ua 🇺🇿uz 🇰🇿kz: RU AdList", - "tags": "ads belarusian беларуская kazakh tatar russian русский ukrainian українська uzbek", - "lang": "be kk tt ru uk uz", + "tags": "ads belarusian беларуская kazakh tatar russian русский ukrainian українська uzbek uk", + "lang": "be kk tt ru uz", "contentURL": "https://raw.githubusercontent.com/easylist/ruadlist/master/RuAdList-uBO.txt", "cdnURLs": [ "https://cdn.jsdelivr.net/gh/dimisa-RUAdList/RUAdListCDN@main/lists/ruadlist.ubo.min.txt", @@ -909,6 +950,16 @@ "contentURL": "https://filters.adtidy.org/extension/ublock/filters/13.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, + "UKR-0": { + "content": "filters", + "group": "regions", + "off": true, + "title": "🇺🇦ua: AdGuard Ukrainian", + "tags": "ads ukraine україна", + "lang": "uk", + "contentURL": "https://filters.adtidy.org/extension/ublock/filters/23.txt", + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, "VIE-1": { "content": "filters", "group": "regions", diff -Nru ublock-origin-1.62.0+dfsg/debian/changelog ublock-origin-1.67.0+dfsg/debian/changelog --- ublock-origin-1.62.0+dfsg/debian/changelog 2025-06-10 15:49:10.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/debian/changelog 2025-10-31 13:56:50.000000000 +0000 @@ -1,3 +1,16 @@ +ublock-origin (1.67.0+dfsg-1~deb13u1) trixie; urgency=medium + + * Backport version 1.67.0 to trixie to improve user experience and add new + filter capabilities. + + -- Markus Koschany Fri, 31 Oct 2025 14:56:50 +0100 + +ublock-origin (1.67.0+dfsg-1) unstable; urgency=medium + + * New upstream version 1.67.0+dfsg. + + -- Markus Koschany Sat, 25 Oct 2025 21:37:39 +0200 + ublock-origin (1.62.0+dfsg-2) unstable; urgency=medium * Fix CVE-2025-4215: diff -Nru ublock-origin-1.62.0+dfsg/debian/control ublock-origin-1.67.0+dfsg/debian/control --- ublock-origin-1.62.0+dfsg/debian/control 2025-06-10 15:49:10.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/debian/control 2025-10-31 13:56:50.000000000 +0000 @@ -8,12 +8,12 @@ Build-Depends: binaryen, debhelper-compat (= 13), - nodejs, node-css-tree, node-js-beautify, + nodejs, python3, wabt -Standards-Version: 4.7.0 +Standards-Version: 4.7.2 Homepage: https://github.com/gorhill/uBlock Vcs-Git: https://salsa.debian.org/webext-team/ublock-origin.git Vcs-Browser: https://salsa.debian.org/webext-team/ublock-origin diff -Nru ublock-origin-1.62.0+dfsg/debian/copyright ublock-origin-1.67.0+dfsg/debian/copyright --- ublock-origin-1.62.0+dfsg/debian/copyright 2025-06-10 15:49:10.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/debian/copyright 2025-10-31 13:56:50.000000000 +0000 @@ -676,4 +676,3 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff -Nru ublock-origin-1.62.0+dfsg/debian/patches/CVE-2025-4215.patch ublock-origin-1.67.0+dfsg/debian/patches/CVE-2025-4215.patch --- ublock-origin-1.62.0+dfsg/debian/patches/CVE-2025-4215.patch 2025-06-10 15:49:10.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/debian/patches/CVE-2025-4215.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -From: Markus Koschany -Date: Tue, 10 Jun 2025 17:20:18 +0200 -Subject: CVE-2025-4215 - -Bug-Debian: https://bugs.debian.org/1104635 -Origin: https://github.com/gorhill/uBlock/commit/eaedaf5b10d2f7857c6b77fbf7d4a80681d4d46c ---- - src/js/1p-filters.js | 4 ++-- - src/js/arglist-parser.js | 4 ++-- - src/js/static-filtering-parser.js | 4 ++-- - src/js/whitelist.js | 6 +++--- - 4 files changed, 9 insertions(+), 9 deletions(-) - -diff --git a/src/js/1p-filters.js b/src/js/1p-filters.js -index 70ce256..b6237a7 100644 ---- a/src/js/1p-filters.js -+++ b/src/js/1p-filters.js -@@ -111,12 +111,12 @@ function currentStateChanged() { - } - - function getEditorText() { -- const text = cmEditor.getValue().replace(/\s+$/, ''); -+ const text = cmEditor.getValue().trimEnd(); - return text === '' ? text : `${text}\n`; - } - - function setEditorText(text) { -- cmEditor.setValue(text.replace(/\s+$/, '') + '\n\n'); -+ cmEditor.setValue(`${text.trimEnd()}\n\n`); - } - - /******************************************************************************/ -diff --git a/src/js/arglist-parser.js b/src/js/arglist-parser.js -index d8200df..708029e 100644 ---- a/src/js/arglist-parser.js -+++ b/src/js/arglist-parser.js -@@ -32,7 +32,7 @@ export class ArglistParser { - this.transform = false; - this.failed = false; - this.reWhitespaceStart = /^\s+/; -- this.reWhitespaceEnd = /\s+$/; -+ this.reWhitespaceEnd = /(?:^|\S)(\s+)$/; - this.reOddTrailingEscape = /(?:^|[^\\])(?:\\\\)*\\$/; - this.reTrailingEscapeChars = /\\+$/; - } -@@ -90,7 +90,7 @@ export class ArglistParser { - } - rightWhitespaceCount(s) { - const match = this.reWhitespaceEnd.exec(s); -- return match === null ? 0 : match[0].length; -+ return match === null ? 0 : match[1].length; - } - indexOfNextArgSeparator(pattern, separatorCode) { - this.argBeg = this.argEnd = separatorCode !== this.separatorCode -diff --git a/src/js/static-filtering-parser.js b/src/js/static-filtering-parser.js -index d3b4ca48..678f625 100644 ---- a/src/js/static-filtering-parser.js -+++ b/src/js/static-filtering-parser.js -@@ -762,7 +762,7 @@ export class AstFilterParser { - this.selectorCompiler = new ExtSelectorCompiler(options); - // Regexes - this.reWhitespaceStart = /^\s+/; -- this.reWhitespaceEnd = /\s+$/; -+ this.reWhitespaceEnd = /(?:^|\S)(\s+)$/; - this.reCommentLine = /^(?:!|#\s|####|\[adblock)/i; - this.reExtAnchor = /(#@?(?:\$\?|\$|%|\?)?#).{1,2}/; - this.reInlineComment = /(?:\s+#).*?$/; -@@ -2737,7 +2737,7 @@ export class AstFilterParser { - - rightWhitespaceCount(s) { - const match = this.reWhitespaceEnd.exec(s); -- return match === null ? 0 : match[0].length; -+ return match === null ? 0 : match[1].length; - } - - nextCommaInCommaSeparatedListString(s, start) { -diff --git a/src/js/whitelist.js b/src/js/whitelist.js -index b8f0eaa..a946f35 100644 ---- a/src/js/whitelist.js -+++ b/src/js/whitelist.js -@@ -101,12 +101,12 @@ uBlockDashboard.patchCodeMirrorEditor(cmEditor); - /******************************************************************************/ - - function getEditorText() { -- let text = cmEditor.getValue().replace(/\s+$/, ''); -- return text === '' ? text : text + '\n'; -+ const text = cmEditor.getValue().trimEnd(); -+ return text === '' ? text : `${text}\n`; - } - - function setEditorText(text) { -- cmEditor.setValue(text.replace(/\s+$/, '') + '\n'); -+ cmEditor.setValue(`${text.trimEnd()}\n`); - } - - /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/debian/patches/series ublock-origin-1.67.0+dfsg/debian/patches/series --- ublock-origin-1.62.0+dfsg/debian/patches/series 2025-06-10 15:49:10.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/debian/patches/series 2025-10-31 13:56:50.000000000 +0000 @@ -1,3 +1,2 @@ disable-nonfree-filters-by-default.patch make-assets.patch -CVE-2025-4215.patch diff -Nru ublock-origin-1.62.0+dfsg/debian/webext-ublock-origin-chromium.lintian-overrides ublock-origin-1.67.0+dfsg/debian/webext-ublock-origin-chromium.lintian-overrides --- ublock-origin-1.62.0+dfsg/debian/webext-ublock-origin-chromium.lintian-overrides 2025-06-10 15:49:10.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/debian/webext-ublock-origin-chromium.lintian-overrides 2025-10-31 13:56:50.000000000 +0000 @@ -1,2 +1,3 @@ # This is a false-positive. privacy-breach-google-adsense + diff -Nru ublock-origin-1.62.0+dfsg/dist/chromium/publish-beta.py ublock-origin-1.67.0+dfsg/dist/chromium/publish-beta.py --- ublock-origin-1.62.0+dfsg/dist/chromium/publish-beta.py 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/dist/chromium/publish-beta.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,190 +0,0 @@ -#!/usr/bin/env python3 - -import datetime -import json -import os -import re -import requests -import shutil -import subprocess -import sys -import tempfile -import time -import zipfile - -from string import Template - -# - Download target (raw) uBlock0.chromium.zip from GitHub -# - This is referred to as "raw" package -# - This will fail if not a dev build -# - Upload uBlock0.chromium.zip to Chrome store -# - Publish uBlock0.chromium.zip to Chrome store - -# Find path to project root -projdir = os.path.split(os.path.abspath(__file__))[0] -while not os.path.isdir(os.path.join(projdir, '.git')): - projdir = os.path.normpath(os.path.join(projdir, '..')) - -# We need a version string to work with -if len(sys.argv) >= 2 and sys.argv[1]: - version = sys.argv[1] -else: - version = input('Github release version: ') -version.strip() -if not re.search('^\d+\.\d+\.\d+(b|rc)\d+$', version): - print('Error: Invalid version string.') - exit(1) - -cs_extension_id = 'cgbcahbpdhpcegmbfconppldiemgcoii' -tmpdir = tempfile.TemporaryDirectory() -raw_zip_filename = 'uBlock0_' + version + '.chromium.zip' -raw_zip_filepath = os.path.join(tmpdir.name, raw_zip_filename) -github_owner = 'gorhill' -github_repo = 'uBlock' - -# Load/save auth secrets -# The tmp directory is excluded from git -ubo_secrets = dict() -ubo_secrets_filename = os.path.join(projdir, 'tmp', 'ubo_secrets') -if os.path.isfile(ubo_secrets_filename): - with open(ubo_secrets_filename) as f: - ubo_secrets = json.load(f) - -def input_secret(prompt, token): - if token in ubo_secrets: - prompt += ' ✔' - prompt += ': ' - value = input(prompt).strip() - if len(value) == 0: - if token not in ubo_secrets: - print('Token error:', token) - exit(1) - value = ubo_secrets[token] - elif token not in ubo_secrets or value != ubo_secrets[token]: - ubo_secrets[token] = value - exists = os.path.isfile(ubo_secrets_filename) - with open(ubo_secrets_filename, 'w') as f: - json.dump(ubo_secrets, f, indent=2) - if not exists: - os.chmod(ubo_secrets_filename, 0o600) - return value - - -# GitHub API token -github_token = input_secret('Github token', 'github_token') -github_auth = 'token ' + github_token - -# -# Get metadata from GitHub about the release -# - -# https://developer.github.com/v3/repos/releases/#get-a-single-release -print('Downloading release info from GitHub...') -release_info_url = 'https://api.github.com/repos/{0}/{1}/releases/tags/{2}'.format(github_owner, github_repo, version) -headers = { 'Authorization': github_auth, } -response = requests.get(release_info_url, headers=headers) -if response.status_code != 200: - print('Error: Release not found: {0}'.format(response.status_code)) - exit(1) -release_info = response.json() - -# -# Extract URL to raw package from metadata -# - -# Find url for uBlock0.chromium.zip -raw_zip_url = '' -for asset in release_info['assets']: - if asset['name'] == raw_zip_filename: - raw_zip_url = asset['url'] -if len(raw_zip_url) == 0: - print('Error: Release asset URL not found') - exit(1) - -# -# Download raw package from GitHub -# - -# https://developer.github.com/v3/repos/releases/#get-a-single-release-asset -print('Downloading raw zip package from GitHub...') -headers = { - 'Authorization': github_auth, - 'Accept': 'application/octet-stream', -} -response = requests.get(raw_zip_url, headers=headers) -# Redirections are transparently handled: -# http://docs.python-requests.org/en/master/user/quickstart/#redirection-and-history -if response.status_code != 200: - print('Error: Downloading raw package failed -- server error {0}'.format(response.status_code)) - exit(1) -with open(raw_zip_filepath, 'wb') as f: - f.write(response.content) -print('Downloaded raw package saved as {0}'.format(raw_zip_filepath)) - -# -# Upload to Chrome store -# - -# Auth tokens -cs_id = input_secret('Chrome store id', 'cs_id') -cs_secret = input_secret('Chrome store secret', 'cs_secret') -cs_refresh = input_secret('Chrome store refresh token', 'cs_refresh') - -print('Uploading to Chrome store...') -with open(raw_zip_filepath, 'rb') as f: - print('Generating access token...') - auth_url = 'https://accounts.google.com/o/oauth2/token' - auth_payload = { - 'client_id': cs_id, - 'client_secret': cs_secret, - 'grant_type': 'refresh_token', - 'refresh_token': cs_refresh, - } - auth_response = requests.post(auth_url, data=auth_payload) - if auth_response.status_code != 200: - print('Error: Auth failed -- server error {0}'.format(auth_response.status_code)) - print(auth_response.text) - exit(1) - response_dict = auth_response.json() - if 'access_token' not in response_dict: - print('Error: Auth failed -- no access token') - exit(1) - # Prepare access token - cs_auth = 'Bearer ' + response_dict['access_token'] - headers = { - 'Authorization': cs_auth, - 'x-goog-api-version': '2', - } - # Upload - print('Uploading package...') - upload_url = 'https://www.googleapis.com/upload/chromewebstore/v1.1/items/{0}'.format(cs_extension_id) - upload_response = requests.put(upload_url, headers=headers, data=f) - f.close() - if upload_response.status_code != 200: - print('Upload failed -- server error {0}'.format(upload_response.status_code)) - print(upload_response.text) - exit(1) - response_dict = upload_response.json(); - if 'uploadState' not in response_dict or response_dict['uploadState'] != 'SUCCESS': - print('Upload failed -- server error {0}'.format(response_dict['uploadState'])) - exit(1) - print('Upload succeeded.') - # Publish - print('Publishing package...') - publish_url = 'https://www.googleapis.com/chromewebstore/v1.1/items/{0}/publish'.format(cs_extension_id) - headers = { - 'Authorization': cs_auth, - 'x-goog-api-version': '2', - 'Content-Length': '0', - } - publish_response = requests.post(publish_url, headers=headers) - if publish_response.status_code != 200: - print('Error: Chrome store publishing failed -- server error {0}'.format(publish_response.status_code)) - exit(1) - response_dict = publish_response.json(); - if 'status' not in response_dict or response_dict['status'][0] != 'OK': - print('Publishing failed -- server error {0}'.format(response_dict['status'])) - exit(1) - print('Publishing succeeded.') - -print('All done.') diff -Nru ublock-origin-1.62.0+dfsg/dist/chromium/publish-stable.py ublock-origin-1.67.0+dfsg/dist/chromium/publish-stable.py --- ublock-origin-1.62.0+dfsg/dist/chromium/publish-stable.py 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/dist/chromium/publish-stable.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,190 +0,0 @@ -#!/usr/bin/env python3 - -import datetime -import json -import os -import re -import requests -import shutil -import subprocess -import sys -import tempfile -import time -import zipfile - -from string import Template - -# - Download target (raw) uBlock0.chromium.zip from GitHub -# - This is referred to as "raw" package -# - This will fail if not a dev build -# - Upload uBlock0.chromium.zip to Chrome store -# - Publish uBlock0.chromium.zip to Chrome store - -# Find path to project root -projdir = os.path.split(os.path.abspath(__file__))[0] -while not os.path.isdir(os.path.join(projdir, '.git')): - projdir = os.path.normpath(os.path.join(projdir, '..')) - -# We need a version string to work with -if len(sys.argv) >= 2 and sys.argv[1]: - version = sys.argv[1] -else: - version = input('Github release version: ') -version.strip() -if not re.search('^\d+\.\d+\.\d+$', version): - print('Error: Invalid version string.') - exit(1) - -cs_extension_id = 'cjpalhdlnbpafiamejdnhcphjbkeiagm' -tmpdir = tempfile.TemporaryDirectory() -raw_zip_filename = 'uBlock0_' + version + '.chromium.zip' -raw_zip_filepath = os.path.join(tmpdir.name, raw_zip_filename) -github_owner = 'gorhill' -github_repo = 'uBlock' - -# Load/save auth secrets -# The tmp directory is excluded from git -ubo_secrets = dict() -ubo_secrets_filename = os.path.join(projdir, 'tmp', 'ubo_secrets') -if os.path.isfile(ubo_secrets_filename): - with open(ubo_secrets_filename) as f: - ubo_secrets = json.load(f) - -def input_secret(prompt, token): - if token in ubo_secrets: - prompt += ' ✔' - prompt += ': ' - value = input(prompt).strip() - if len(value) == 0: - if token not in ubo_secrets: - print('Token error:', token) - exit(1) - value = ubo_secrets[token] - elif token not in ubo_secrets or value != ubo_secrets[token]: - ubo_secrets[token] = value - exists = os.path.isfile(ubo_secrets_filename) - with open(ubo_secrets_filename, 'w') as f: - json.dump(ubo_secrets, f, indent=2) - if not exists: - os.chmod(ubo_secrets_filename, 0o600) - return value - - -# GitHub API token -github_token = input_secret('Github token', 'github_token') -github_auth = 'token ' + github_token - -# -# Get metadata from GitHub about the release -# - -# https://developer.github.com/v3/repos/releases/#get-a-single-release -print('Downloading release info from GitHub...') -release_info_url = 'https://api.github.com/repos/{0}/{1}/releases/tags/{2}'.format(github_owner, github_repo, version) -headers = { 'Authorization': github_auth, } -response = requests.get(release_info_url, headers=headers) -if response.status_code != 200: - print('Error: Release not found: {0}'.format(response.status_code)) - exit(1) -release_info = response.json() - -# -# Extract URL to raw package from metadata -# - -# Find url for uBlock0.chromium.zip -raw_zip_url = '' -for asset in release_info['assets']: - if asset['name'] == raw_zip_filename: - raw_zip_url = asset['url'] -if len(raw_zip_url) == 0: - print('Error: Release asset URL not found') - exit(1) - -# -# Download raw package from GitHub -# - -# https://developer.github.com/v3/repos/releases/#get-a-single-release-asset -print('Downloading raw zip package from GitHub...') -headers = { - 'Authorization': github_auth, - 'Accept': 'application/octet-stream', -} -response = requests.get(raw_zip_url, headers=headers) -# Redirections are transparently handled: -# http://docs.python-requests.org/en/master/user/quickstart/#redirection-and-history -if response.status_code != 200: - print('Error: Downloading raw package failed -- server error {0}'.format(response.status_code)) - exit(1) -with open(raw_zip_filepath, 'wb') as f: - f.write(response.content) -print('Downloaded raw package saved as {0}'.format(raw_zip_filepath)) - -# -# Upload to Chrome store -# - -# Auth tokens -cs_id = input_secret('Chrome store id', 'cs_id') -cs_secret = input_secret('Chrome store secret', 'cs_secret') -cs_refresh = input_secret('Chrome store refresh token', 'cs_refresh') - -print('Uploading to Chrome store...') -with open(raw_zip_filepath, 'rb') as f: - print('Generating access token...') - auth_url = 'https://accounts.google.com/o/oauth2/token' - auth_payload = { - 'client_id': cs_id, - 'client_secret': cs_secret, - 'grant_type': 'refresh_token', - 'refresh_token': cs_refresh, - } - auth_response = requests.post(auth_url, data=auth_payload) - if auth_response.status_code != 200: - print('Error: Auth failed -- server error {0}'.format(auth_response.status_code)) - print(auth_response.text) - exit(1) - response_dict = auth_response.json() - if 'access_token' not in response_dict: - print('Error: Auth failed -- no access token') - exit(1) - # Prepare access token - cs_auth = 'Bearer ' + response_dict['access_token'] - headers = { - 'Authorization': cs_auth, - 'x-goog-api-version': '2', - } - # Upload - print('Uploading package...') - upload_url = 'https://www.googleapis.com/upload/chromewebstore/v1.1/items/{0}'.format(cs_extension_id) - upload_response = requests.put(upload_url, headers=headers, data=f) - f.close() - if upload_response.status_code != 200: - print('Upload failed -- server error {0}'.format(upload_response.status_code)) - print(upload_response.text) - exit(1) - response_dict = upload_response.json(); - if 'uploadState' not in response_dict or response_dict['uploadState'] != 'SUCCESS': - print('Upload failed -- server error {0}'.format(response_dict['uploadState'])) - exit(1) - print('Upload succeeded.') - # Publish - print('Publishing package...') - publish_url = 'https://www.googleapis.com/chromewebstore/v1.1/items/{0}/publish'.format(cs_extension_id) - headers = { - 'Authorization': cs_auth, - 'x-goog-api-version': '2', - 'Content-Length': '0', - } - publish_response = requests.post(publish_url, headers=headers) - if publish_response.status_code != 200: - print('Error: Chrome store publishing failed -- server error {0}'.format(publish_response.status_code)) - exit(1) - response_dict = publish_response.json(); - if 'status' not in response_dict or response_dict['status'][0] != 'OK': - print('Publishing failed -- server error {0}'.format(response_dict['status'])) - exit(1) - print('Publishing succeeded.') - -print('All done.') diff -Nru ublock-origin-1.62.0+dfsg/dist/firefox/publish-signed-beta.py ublock-origin-1.67.0+dfsg/dist/firefox/publish-signed-beta.py --- ublock-origin-1.62.0+dfsg/dist/firefox/publish-signed-beta.py 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/dist/firefox/publish-signed-beta.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,331 +0,0 @@ -#!/usr/bin/env python3 - -import datetime -import json -import jwt -import os -import re -import requests -import shutil -import subprocess -import sys -import tempfile -import time -import zipfile - -from string import Template - -# - Download target (raw) uBlock0.firefox.xpi from GitHub -# - This is referred to as "raw" package -# - This will fail if not a dev build -# - Modify raw package to make it self-hosted -# - This is referred to as "unsigned" package -# - Ask AMO to sign uBlock0.firefox.xpi -# - Generate JWT to be used for communication with server -# - Upload unsigned package to AMO -# - Wait for a valid download URL for signed package -# - Download signed package as uBlock0.firefox.signed.xpi -# - This is referred to as "signed" package -# - Upload uBlock0.firefox.signed.xpi to GitHub -# - Remove uBlock0.firefox.xpi from GitHub -# - Modify updates.json to point to new version -# - Commit changes to repo - -# Find path to project root -projdir = os.path.split(os.path.abspath(__file__))[0] -while not os.path.isdir(os.path.join(projdir, '.git')): - projdir = os.path.normpath(os.path.join(projdir, '..')) -# Check that found project root is valid -version_filepath = os.path.join(projdir, 'dist', 'version') -if not os.path.isfile(version_filepath): - print('Version file not found.') - exit(1) - -# We need a version string to work with -if len(sys.argv) >= 2 and sys.argv[1]: - tag_version = sys.argv[1] -else: - tag_version = input('Github release version: ') -tag_version.strip() -match = re.search('^(\d+\.\d+\.\d+)(?:(b|rc)(\d+))?$', tag_version) -if not match: - print('Error: Invalid version string.') - exit(1) -ext_version = match.group(1); -if match.group(2): - revision = int(match.group(3)) - if match.group(2) == 'rc': - revision += 100; - ext_version += '.' + str(revision) - -extension_id = 'uBlock0@raymondhill.net' -tmpdir = tempfile.TemporaryDirectory() -raw_xpi_filename = 'uBlock0_' + tag_version + '.firefox.xpi' -raw_xpi_filepath = os.path.join(tmpdir.name, raw_xpi_filename) -unsigned_xpi_filepath = os.path.join(tmpdir.name, 'uBlock0.firefox.unsigned.xpi') -signed_xpi_filename = 'uBlock0_' + tag_version + '.firefox.signed.xpi' -signed_xpi_filepath = os.path.join(tmpdir.name, signed_xpi_filename) -github_owner = 'gorhill' -github_repo = 'uBlock' - -# Load/save auth secrets -# The tmp directory is excluded from git -ubo_secrets = dict() -ubo_secrets_filename = os.path.join(projdir, 'tmp', 'ubo_secrets') -if os.path.isfile(ubo_secrets_filename): - with open(ubo_secrets_filename) as f: - ubo_secrets = json.load(f) - -def input_secret(prompt, token): - if token in ubo_secrets: - prompt += ' ✔' - prompt += ': ' - value = input(prompt).strip() - if len(value) == 0: - if token not in ubo_secrets: - print('Token error:', token) - exit(1) - value = ubo_secrets[token] - elif token not in ubo_secrets or value != ubo_secrets[token]: - ubo_secrets[token] = value - exists = os.path.isfile(ubo_secrets_filename) - with open(ubo_secrets_filename, 'w') as f: - json.dump(ubo_secrets, f, indent=2) - if not exists: - os.chmod(ubo_secrets_filename, 0o600) - return value - -# GitHub API token -github_token = input_secret('Github token', 'github_token') -github_auth = 'token ' + github_token - -# -# Get metadata from GitHub about the release -# - -# https://developer.github.com/v3/repos/releases/#get-a-single-release -print('Downloading release info from GitHub...') -release_info_url = 'https://api.github.com/repos/{0}/{1}/releases/tags/{2}'.format(github_owner, github_repo, tag_version) -headers = { 'Authorization': github_auth, } -response = requests.get(release_info_url, headers=headers) -if response.status_code != 200: - print('Error: Release not found: {0}'.format(response.status_code)) - exit(1) -release_info = response.json() - -# -# Extract URL to raw package from metadata -# - -# Find url for uBlock0.firefox.xpi -raw_xpi_url = '' -for asset in release_info['assets']: - if asset['name'] == signed_xpi_filename: - print('Error: Found existing signed self-hosted package.') - exit(1) - if asset['name'] == raw_xpi_filename: - raw_xpi_url = asset['url'] -if len(raw_xpi_url) == 0: - print('Error: Release asset URL not found') - exit(1) - -# -# Download raw package from GitHub -# - -# https://developer.github.com/v3/repos/releases/#get-a-single-release-asset -print('Downloading raw xpi package from GitHub...') -headers = { - 'Authorization': github_auth, - 'Accept': 'application/octet-stream', -} -response = requests.get(raw_xpi_url, headers=headers) -# Redirections are transparently handled: -# http://docs.python-requests.org/en/master/user/quickstart/#redirection-and-history -if response.status_code != 200: - print('Error: Downloading raw package failed -- server error {0}'.format(response.status_code)) - exit(1) -with open(raw_xpi_filepath, 'wb') as f: - f.write(response.content) -print('Downloaded raw package saved as {0}'.format(raw_xpi_filepath)) - -# -# Convert the package to a self-hosted one: add `update_url` to the manifest -# -min_browser_version = '68'; - -print('Converting raw xpi package into self-hosted xpi package...') -with zipfile.ZipFile(raw_xpi_filepath, 'r') as zipin: - with zipfile.ZipFile(unsigned_xpi_filepath, 'w') as zipout: - for item in zipin.infolist(): - data = zipin.read(item.filename) - if item.filename == 'manifest.json': - manifest = json.loads(bytes.decode(data)) - min_browser_version = manifest['browser_specific_settings']['gecko']['strict_min_version'] - manifest['browser_specific_settings']['gecko']['update_url'] = 'https://raw.githubusercontent.com/{0}/{1}/master/dist/firefox/updates.json'.format(github_owner, github_repo) - data = json.dumps(manifest, indent=2, separators=(',', ': '), sort_keys=True).encode() - zipout.writestr(item, data) - -# -# Ask AMO to sign the self-hosted package -# - https://developer.mozilla.org/en-US/Add-ons/Distribution#Distributing_your_add-on -# - https://pyjwt.readthedocs.io/en/latest/usage.html -# - https://addons-server.readthedocs.io/en/latest/topics/api/auth.html -# - https://addons-server.readthedocs.io/en/latest/topics/api/signing.html -# - -amo_api_key = '' -amo_secret = '' - -def get_jwt_auth(): - global amo_api_key - if amo_api_key == '': - amo_api_key = input_secret('AMO API key', 'amo_api_key') - global amo_secret - if amo_secret == '': - amo_secret = input_secret('AMO API secret', 'amo_secret') - amo_nonce = os.urandom(8).hex() - jwt_payload = { - 'iss': amo_api_key, - 'jti': amo_nonce, - 'iat': datetime.datetime.utcnow(), - 'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=15), - } - return 'JWT ' + jwt.encode(jwt_payload, amo_secret) - -print('Ask AMO to sign self-hosted xpi package...') -with open(unsigned_xpi_filepath, 'rb') as f: - # https://blog.mozilla.org/addons/2019/11/11/security-improvements-in-amo-upload-tools/ - # "We recommend allowing up to 15 minutes." - interval = 60 # check every 60 seconds - countdown = 60 * 60 / interval # for at most 60 minutes - headers = { 'Authorization': get_jwt_auth(), } - data = { 'channel': 'unlisted' } - files = { 'upload': f, } - signing_url = 'https://addons.mozilla.org/api/v4/addons/{0}/versions/{1}/'.format(extension_id, ext_version) - print('Submitting package to be signed...') - response = requests.put(signing_url, headers=headers, data=data, files=files) - if response.status_code != 202: - print('Error: Creating new version failed -- server error {0}'.format(response.status_code)) - print(response.text) - exit(1) - print('Request for signing self-hosted xpi package succeeded.') - signing_request_response = response.json(); - f.close() - print('Waiting for AMO to process the request to sign the self-hosted xpi package...') - # Wait for signed package to be ready - signing_check_url = signing_request_response['url'] - while True: - time.sleep(interval) - sys.stdout.write('.') - sys.stdout.flush() - countdown -= 1 - if countdown <= 0: - print('Error: AMO signing timed out') - exit(1) - headers = { 'Authorization': get_jwt_auth(), } - response = requests.get(signing_check_url, headers=headers) - if response.status_code != 200: - print('Error: AMO signing failed -- server error {0}'.format(response.status_code)) - print(response.text) - exit(1) - signing_check_response = response.json() - if not signing_check_response['processed']: - continue - if not signing_check_response['valid']: - print('Error: AMO validation failed') - print(response.text) - exit(1) - if not signing_check_response['files'] or len(signing_check_response['files']) == 0: - continue - if not signing_check_response['files'][0]['signed']: - continue - if not signing_check_response['files'][0]['download_url']: - print('Error: AMO signing failed') - print(response.text) - exit(1) - print('\r') - print('Self-hosted xpi package successfully signed.') - download_url = signing_check_response['files'][0]['download_url'] - print('Downloading signed self-hosted xpi package from {0}...'.format(download_url)) - response = requests.get(download_url, headers=headers) - if response.status_code != 200: - print('Error: Download signed package failed -- server error {0}'.format(response.status_code)) - print(response.text) - exit(1) - with open(signed_xpi_filepath, 'wb') as f: - f.write(response.content) - f.close() - print('Signed self-hosted xpi package downloaded.') - break - -# -# Upload signed package to GitHub -# - -# https://developer.github.com/v3/repos/releases/#upload-a-release-asset -print('Uploading signed self-hosted xpi package to GitHub...') -with open(signed_xpi_filepath, 'rb') as f: - url = release_info['upload_url'].replace('{?name,label}', '?name=' + signed_xpi_filename) - headers = { - 'Authorization': github_auth, - 'Content-Type': 'application/zip', - } - response = requests.post(url, headers=headers, data=f.read()) - if response.status_code != 201: - print('Error: Upload signed package failed -- server error: {0}'.format(response.status_code)) - exit(1) - -# -# Remove raw package from GitHub -# - -# https://developer.github.com/v3/repos/releases/#delete-a-release-asset -print('Remove raw xpi package from GitHub...') -headers = { 'Authorization': github_auth, } -response = requests.delete(raw_xpi_url, headers=headers) -if response.status_code != 204: - print('Error: Deletion of raw package failed -- server error: {0}'.format(response.status_code)) - -# -# Update updates.json to point to new package -- but only if just-signed -# package is higher version than current one. -# - -# Be sure we are in sync with potentially modified files on remote -r = subprocess.run(['git', 'pull', 'origin', 'master'], stdout=subprocess.PIPE) -rout = bytes.decode(r.stdout).strip() - -def int_from_version(version): - parts = version.split('.') - if len(parts) == 3: - parts.append('0') - return int(parts[0])*10e9 + int(parts[1])*10e6 + int(parts[2])*10e3 + int(parts[3]) - -print('Update GitHub to point to newly signed self-hosted xpi package...') -updates_json_filepath = os.path.join(projdir, 'dist', 'firefox', 'updates.json') -with open(updates_json_filepath) as f: - updates_json = json.load(f) - f.close() - previous_version = updates_json['addons'][extension_id]['updates'][0]['version'] - if int_from_version(ext_version) > int_from_version(previous_version): - with open(os.path.join(projdir, 'dist', 'firefox', 'updates.template.json')) as f: - template_json = Template(f.read()) - f.close() - updates_json = template_json.substitute(ext_version=ext_version, tag_version=tag_version, min_browser_version=min_browser_version) - with open(updates_json_filepath, 'w') as f: - f.write(updates_json) - f.close() - # - Stage the changed file - r = subprocess.run(['git', 'status', '-s', updates_json_filepath], stdout=subprocess.PIPE) - rout = bytes.decode(r.stdout).strip() - if len(rout) >= 2 and rout[1] == 'M': - subprocess.run(['git', 'add', updates_json_filepath]) - # - Commit the staged file - r = subprocess.run(['git', 'status', '-s', updates_json_filepath], stdout=subprocess.PIPE) - rout = bytes.decode(r.stdout).strip() - if len(rout) >= 2 and rout[0] == 'M': - subprocess.run(['git', 'commit', '-m', 'Make Firefox dev build auto-update', updates_json_filepath]) - subprocess.run(['git', 'push', 'origin', 'HEAD']) - -print('All done.') diff -Nru ublock-origin-1.62.0+dfsg/dist/firefox/updates.json ublock-origin-1.67.0+dfsg/dist/firefox/updates.json --- ublock-origin-1.62.0+dfsg/dist/firefox/updates.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/dist/firefox/updates.json 2025-10-25 19:32:51.000000000 +0000 @@ -1,13 +1,17 @@ { - "addons": { - "uBlock0@raymondhill.net": { - "updates": [ - { - "version": "1.61.3.103", - "browser_specific_settings": { "gecko": { "strict_min_version": "78.0" } }, - "update_link": "https://github.com/gorhill/uBlock/releases/download/1.61.3rc3/uBlock0_1.61.3rc3.firefox.signed.xpi" + "addons": { + "uBlock0@raymondhill.net": { + "updates": [ + { + "version": "1.66.5.2", + "browser_specific_settings": { + "gecko": { + "strict_min_version": "92.0" + } + }, + "update_link": "https://github.com/gorhill/uBlock/releases/download/1.66.5b2/uBlock0_1.66.5b2.firefox.signed.xpi" + } + ] } - ] } - } -} +} \ No newline at end of file diff -Nru ublock-origin-1.62.0+dfsg/dist/firefox/updates.template.json ublock-origin-1.67.0+dfsg/dist/firefox/updates.template.json --- ublock-origin-1.62.0+dfsg/dist/firefox/updates.template.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/dist/firefox/updates.template.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -{ - "addons": { - "uBlock0@raymondhill.net": { - "updates": [ - { - "version": "$ext_version", - "browser_specific_settings": { "gecko": { "strict_min_version": "$min_browser_version" } }, - "update_link": "https://github.com/gorhill/uBlock/releases/download/$tag_version/uBlock0_$tag_version.firefox.signed.xpi" - } - ] - } - } -} diff -Nru ublock-origin-1.62.0+dfsg/dist/mv3/chromium/publish-beta.py ublock-origin-1.67.0+dfsg/dist/mv3/chromium/publish-beta.py --- ublock-origin-1.62.0+dfsg/dist/mv3/chromium/publish-beta.py 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/dist/mv3/chromium/publish-beta.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,195 +0,0 @@ -#!/usr/bin/env python3 - -import datetime -import json -import os -import re -import requests -import shutil -import subprocess -import sys -import tempfile -import time -import zipfile - -from string import Template - -# - Download target (raw) uBOLite_*.chromium.mv3.zip from GitHub -# - This is referred to as "raw" package -# - This will fail if not a dev build -# - Upload uBOLite_*.chromium.mv3.zip to Chrome store -# - Publish uBOLite_*.chromium.mv3.zip to Chrome store - -# Find path to project root -projdir = os.path.split(os.path.abspath(__file__))[0] -while not os.path.isdir(os.path.join(projdir, '.git')): - projdir = os.path.normpath(os.path.join(projdir, '..')) - -# We need a version string to work with -if len(sys.argv) >= 2 and sys.argv[1]: - version = sys.argv[1] -else: - version = input('Github release version: ') -version.strip() -if not re.search('^uBOLite_\d+\.\d+\.\d+\.\d+$', version): - print('Error: Invalid version string.') - exit(1) - -cs_extension_id = 'ddkjiahejlhfcafbddmgiahcphecmpfh' -tmpdir = tempfile.TemporaryDirectory() -raw_zip_filename = '' -raw_zip_filepath = '' -github_owner = 'gorhill' -github_repo = 'uBlock' - -# Load/save auth secrets -# The build directory is excluded from git -ubo_secrets = dict() -ubo_secrets_filename = os.path.join(projdir, 'dist', 'build', 'ubo_secrets') -if os.path.isfile(ubo_secrets_filename): - with open(ubo_secrets_filename) as f: - ubo_secrets = json.load(f) - -def input_secret(prompt, token): - if token in ubo_secrets: - prompt += ' ✔' - prompt += ': ' - value = input(prompt).strip() - if len(value) == 0: - if token not in ubo_secrets: - print('Token error:', token) - exit(1) - value = ubo_secrets[token] - elif token not in ubo_secrets or value != ubo_secrets[token]: - ubo_secrets[token] = value - exists = os.path.isfile(ubo_secrets_filename) - with open(ubo_secrets_filename, 'w') as f: - json.dump(ubo_secrets, f, indent=2) - if not exists: - os.chmod(ubo_secrets_filename, 0o600) - return value - - -# GitHub API token -github_token = input_secret('Github token', 'github_token') -github_auth = 'token ' + github_token - -# -# Get metadata from GitHub about the release -# - -# https://developer.github.com/v3/repos/releases/#get-a-single-release -print('Downloading release info from GitHub...') -release_info_url = 'https://api.github.com/repos/{0}/{1}/releases/tags/{2}'.format(github_owner, github_repo, version) -headers = { 'Authorization': github_auth, } -response = requests.get(release_info_url, headers=headers) -if response.status_code != 200: - print('Error: Release not found: {0}'.format(response.status_code)) - exit(1) -release_info = response.json() - -# -# Extract URL to raw package from metadata -# - -# Find url for uBOLite_*.chromium.mv3.zip -raw_zip_url = '' -for asset in release_info['assets']: - if re.search('uBOLite_\d+.\d+.\d+.\d+.chromium.mv3.zip', asset['name']): - raw_zip_url = asset['url'] - raw_zip_filename = asset['name'] - raw_zip_filepath = os.path.join(tmpdir.name, raw_zip_filename) -if len(raw_zip_url) == 0: - print('Error: Release asset URL not found') - exit(1) -if len(raw_zip_filepath) == 0: - print('Error: Invalid release asset file not set') - exit(1) - -# -# Download raw package from GitHub -# - -# https://developer.github.com/v3/repos/releases/#get-a-single-release-asset -print('Downloading raw zip package from GitHub...') -headers = { - 'Authorization': github_auth, - 'Accept': 'application/octet-stream', -} -response = requests.get(raw_zip_url, headers=headers) -# Redirections are transparently handled: -# http://docs.python-requests.org/en/master/user/quickstart/#redirection-and-history -if response.status_code != 200: - print('Error: Downloading raw package failed -- server error {0}'.format(response.status_code)) - exit(1) -with open(raw_zip_filepath, 'wb') as f: - f.write(response.content) -print('Downloaded raw package saved as {0}'.format(raw_zip_filepath)) - -# -# Upload to Chrome store -# - -# Auth tokens -cs_id = input_secret('Chrome store id', 'cs_id') -cs_secret = input_secret('Chrome store secret', 'cs_secret') -cs_refresh = input_secret('Chrome store refresh token', 'cs_refresh') - -print('Uploading to Chrome store...') -with open(raw_zip_filepath, 'rb') as f: - print('Generating access token...') - auth_url = 'https://accounts.google.com/o/oauth2/token' - auth_payload = { - 'client_id': cs_id, - 'client_secret': cs_secret, - 'grant_type': 'refresh_token', - 'refresh_token': cs_refresh, - } - auth_response = requests.post(auth_url, data=auth_payload) - if auth_response.status_code != 200: - print('Error: Auth failed -- server error {0}'.format(auth_response.status_code)) - print(auth_response.text) - exit(1) - response_dict = auth_response.json() - if 'access_token' not in response_dict: - print('Error: Auth failed -- no access token') - exit(1) - # Prepare access token - cs_auth = 'Bearer ' + response_dict['access_token'] - headers = { - 'Authorization': cs_auth, - 'x-goog-api-version': '2', - } - # Upload - print('Uploading package...') - upload_url = 'https://www.googleapis.com/upload/chromewebstore/v1.1/items/{0}'.format(cs_extension_id) - upload_response = requests.put(upload_url, headers=headers, data=f) - f.close() - if upload_response.status_code != 200: - print('Upload failed -- server error {0}'.format(upload_response.status_code)) - print(upload_response.text) - exit(1) - response_dict = upload_response.json(); - if 'uploadState' not in response_dict or response_dict['uploadState'] != 'SUCCESS': - print('Upload failed -- server error {0}'.format(response_dict['uploadState'])) - exit(1) - print('Upload succeeded.') - # Publish - print('Publishing package...') - publish_url = 'https://www.googleapis.com/chromewebstore/v1.1/items/{0}/publish'.format(cs_extension_id) - headers = { - 'Authorization': cs_auth, - 'x-goog-api-version': '2', - 'Content-Length': '0', - } - publish_response = requests.post(publish_url, headers=headers) - if publish_response.status_code != 200: - print('Error: Chrome store publishing failed -- server error {0}'.format(publish_response.status_code)) - exit(1) - response_dict = publish_response.json(); - if 'status' not in response_dict or response_dict['status'][0] != 'OK': - print('Publishing failed -- server error {0}'.format(response_dict['status'])) - exit(1) - print('Publishing succeeded.') - -print('All done.') diff -Nru ublock-origin-1.62.0+dfsg/dist/mv3/firefox/publish-signed-beta.py ublock-origin-1.67.0+dfsg/dist/mv3/firefox/publish-signed-beta.py --- ublock-origin-1.62.0+dfsg/dist/mv3/firefox/publish-signed-beta.py 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/dist/mv3/firefox/publish-signed-beta.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,326 +0,0 @@ -#!/usr/bin/env python3 - -import datetime -import json -import jwt -import os -import re -import requests -import shutil -import subprocess -import sys -import tempfile -import time -import zipfile - -from string import Template - -# - Download target (raw) uBlock0.firefox.xpi from GitHub -# - This is referred to as "raw" package -# - This will fail if not a dev build -# - Modify raw package to make it self-hosted -# - This is referred to as "unsigned" package -# - Ask AMO to sign uBlock0.firefox.xpi -# - Generate JWT to be used for communication with server -# - Upload unsigned package to AMO -# - Wait for a valid download URL for signed package -# - Download signed package as uBlock0.firefox.signed.xpi -# - This is referred to as "signed" package -# - Upload uBlock0.firefox.signed.xpi to GitHub -# - Remove uBlock0.firefox.xpi from GitHub -# - Modify updates.json to point to new version -# - Commit changes to repo - -# Find path to project root -projdir = os.path.split(os.path.abspath(__file__))[0] -while not os.path.isdir(os.path.join(projdir, '.git')): - projdir = os.path.normpath(os.path.join(projdir, '..')) -# Check that found project root is valid -version_filepath = os.path.join(projdir, 'dist', 'version') -if not os.path.isfile(version_filepath): - print('Version file not found.') - exit(1) - -# We need a version string to work with -if len(sys.argv) >= 2 and sys.argv[1]: - tag_version = sys.argv[1] -else: - tag_version = input('Github release version: ') -tag_version.strip() -match = re.search('^uBOLite_(\d+\.\d+\.\d+.\d+)$', tag_version) -if not match: - print('Error: Invalid version string.') - exit(1) -ext_version = match.group(1); - -extension_id = 'uBOLite@raymondhill.net' -tmpdir = tempfile.TemporaryDirectory() -raw_xpi_filename = tag_version + '.firefox.mv3.xpi' -raw_xpi_filepath = os.path.join(tmpdir.name, raw_xpi_filename) -unsigned_xpi_filepath = os.path.join(tmpdir.name, 'uBOLite.firefox.unsigned.xpi') -signed_xpi_filename = tag_version + '.firefox.signed.mv3.xpi' -signed_xpi_filepath = os.path.join(tmpdir.name, signed_xpi_filename) -github_owner = 'gorhill' -github_repo = 'uBlock' - -# Load/save auth secrets -# The tmp directory is excluded from git -ubo_secrets = dict() -ubo_secrets_filename = os.path.join(projdir, 'tmp', 'ubo_secrets') -if os.path.isfile(ubo_secrets_filename): - with open(ubo_secrets_filename) as f: - ubo_secrets = json.load(f) - -def input_secret(prompt, token): - if token in ubo_secrets: - prompt += ' ✔' - prompt += ': ' - value = input(prompt).strip() - if len(value) == 0: - if token not in ubo_secrets: - print('Token error:', token) - exit(1) - value = ubo_secrets[token] - elif token not in ubo_secrets or value != ubo_secrets[token]: - ubo_secrets[token] = value - exists = os.path.isfile(ubo_secrets_filename) - with open(ubo_secrets_filename, 'w') as f: - json.dump(ubo_secrets, f, indent=2) - if not exists: - os.chmod(ubo_secrets_filename, 0o600) - return value - -# GitHub API token -github_token = input_secret('Github token', 'github_token') -github_auth = 'token ' + github_token - -# -# Get metadata from GitHub about the release -# - -# https://developer.github.com/v3/repos/releases/#get-a-single-release -print('Downloading release info from GitHub...') -release_info_url = 'https://api.github.com/repos/{0}/{1}/releases/tags/{2}'.format(github_owner, github_repo, tag_version) -headers = { 'Authorization': github_auth, } -response = requests.get(release_info_url, headers=headers) -if response.status_code != 200: - print('Error: Release not found: {0}'.format(response.status_code)) - exit(1) -release_info = response.json() - -# -# Extract URL to raw package from metadata -# - -# Find url for uBlock0.firefox.xpi -raw_xpi_url = '' -for asset in release_info['assets']: - if asset['name'] == signed_xpi_filename: - print('Error: Found existing signed self-hosted package.') - exit(1) - if asset['name'] == raw_xpi_filename: - raw_xpi_url = asset['url'] -if len(raw_xpi_url) == 0: - print('Error: Release asset URL not found') - exit(1) - -# -# Download raw package from GitHub -# - -# https://developer.github.com/v3/repos/releases/#get-a-single-release-asset -print('Downloading raw xpi package from GitHub...') -headers = { - 'Authorization': github_auth, - 'Accept': 'application/octet-stream', -} -response = requests.get(raw_xpi_url, headers=headers) -# Redirections are transparently handled: -# http://docs.python-requests.org/en/master/user/quickstart/#redirection-and-history -if response.status_code != 200: - print('Error: Downloading raw package failed -- server error {0}'.format(response.status_code)) - exit(1) -with open(raw_xpi_filepath, 'wb') as f: - f.write(response.content) -print('Downloaded raw package saved as {0}'.format(raw_xpi_filepath)) - -# -# Convert the package to a self-hosted one: add `update_url` to the manifest -# -min_browser_version = '114.0'; - -print('Converting raw xpi package into self-hosted xpi package...') -with zipfile.ZipFile(raw_xpi_filepath, 'r') as zipin: - with zipfile.ZipFile(unsigned_xpi_filepath, 'w') as zipout: - for item in zipin.infolist(): - data = zipin.read(item.filename) - if item.filename == 'manifest.json': - manifest = json.loads(bytes.decode(data)) - min_browser_version = manifest['browser_specific_settings']['gecko']['strict_min_version'] - manifest['browser_specific_settings']['gecko']['update_url'] = 'https://raw.githubusercontent.com/{0}/{1}/master/dist/mv3/firefox/updates.json'.format(github_owner, github_repo) - data = json.dumps(manifest, indent=2, separators=(',', ': '), sort_keys=True).encode() - zipout.writestr(item, data) - -# -# Ask AMO to sign the self-hosted package -# - https://developer.mozilla.org/en-US/Add-ons/Distribution#Distributing_your_add-on -# - https://pyjwt.readthedocs.io/en/latest/usage.html -# - https://addons-server.readthedocs.io/en/latest/topics/api/auth.html -# - https://addons-server.readthedocs.io/en/latest/topics/api/signing.html -# - -amo_api_key = '' -amo_secret = '' - -def get_jwt_auth(): - global amo_api_key - if amo_api_key == '': - amo_api_key = input_secret('AMO API key', 'amo_api_key') - global amo_secret - if amo_secret == '': - amo_secret = input_secret('AMO API secret', 'amo_secret') - amo_nonce = os.urandom(8).hex() - jwt_payload = { - 'iss': amo_api_key, - 'jti': amo_nonce, - 'iat': datetime.datetime.utcnow(), - 'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=15), - } - return 'JWT ' + jwt.encode(jwt_payload, amo_secret) - -print('Ask AMO to sign self-hosted xpi package...') -with open(unsigned_xpi_filepath, 'rb') as f: - # https://blog.mozilla.org/addons/2019/11/11/security-improvements-in-amo-upload-tools/ - # "We recommend allowing up to 15 minutes." - interval = 60 # check every 60 seconds - countdown = 60 * 60 / interval # for at most 60 minutes - headers = { 'Authorization': get_jwt_auth(), } - data = { 'channel': 'unlisted' } - files = { 'upload': f, } - signing_url = 'https://addons.mozilla.org/api/v4/addons/{0}/versions/{1}/'.format(extension_id, ext_version) - print('Submitting package to be signed...') - response = requests.put(signing_url, headers=headers, data=data, files=files) - if response.status_code != 202: - print('Error: Creating new version failed -- server error {0}'.format(response.status_code)) - print(response.text) - exit(1) - print('Request for signing self-hosted xpi package succeeded.') - signing_request_response = response.json(); - f.close() - print('Waiting for AMO to process the request to sign the self-hosted xpi package...') - # Wait for signed package to be ready - signing_check_url = signing_request_response['url'] - while True: - time.sleep(interval) - sys.stdout.write('.') - sys.stdout.flush() - countdown -= 1 - if countdown <= 0: - print('Error: AMO signing timed out') - exit(1) - headers = { 'Authorization': get_jwt_auth(), } - response = requests.get(signing_check_url, headers=headers) - if response.status_code != 200: - print('Error: AMO signing failed -- server error {0}'.format(response.status_code)) - print(response.text) - exit(1) - signing_check_response = response.json() - if not signing_check_response['processed']: - continue - if not signing_check_response['valid']: - print('Error: AMO validation failed') - print(response.text) - exit(1) - if not signing_check_response['files'] or len(signing_check_response['files']) == 0: - continue - if not signing_check_response['files'][0]['signed']: - continue - if not signing_check_response['files'][0]['download_url']: - print('Error: AMO signing failed') - print(response.text) - exit(1) - print('\r') - print('Self-hosted xpi package successfully signed.') - download_url = signing_check_response['files'][0]['download_url'] - print('Downloading signed self-hosted xpi package from {0}...'.format(download_url)) - response = requests.get(download_url, headers=headers) - if response.status_code != 200: - print('Error: Download signed package failed -- server error {0}'.format(response.status_code)) - print(response.text) - exit(1) - with open(signed_xpi_filepath, 'wb') as f: - f.write(response.content) - f.close() - print('Signed self-hosted xpi package downloaded.') - break - -# -# Upload signed package to GitHub -# - -# https://developer.github.com/v3/repos/releases/#upload-a-release-asset -print('Uploading signed self-hosted xpi package to GitHub...') -with open(signed_xpi_filepath, 'rb') as f: - url = release_info['upload_url'].replace('{?name,label}', '?name=' + signed_xpi_filename) - headers = { - 'Authorization': github_auth, - 'Content-Type': 'application/zip', - } - response = requests.post(url, headers=headers, data=f.read()) - if response.status_code != 201: - print('Error: Upload signed package failed -- server error: {0}'.format(response.status_code)) - exit(1) - -# -# Remove raw package from GitHub -# - -# https://developer.github.com/v3/repos/releases/#delete-a-release-asset -print('Remove raw xpi package from GitHub...') -headers = { 'Authorization': github_auth, } -response = requests.delete(raw_xpi_url, headers=headers) -if response.status_code != 204: - print('Error: Deletion of raw package failed -- server error: {0}'.format(response.status_code)) - -# -# Update updates.json to point to new package -- but only if just-signed -# package is higher version than current one. -# - -# Be sure we are in sync with potentially modified files on remote -r = subprocess.run(['git', 'pull', 'origin', 'master'], stdout=subprocess.PIPE) -rout = bytes.decode(r.stdout).strip() - -def int_from_version(version): - parts = version.split('.') - if len(parts) == 3: - parts.append('0') - return int(parts[0])*10e9 + int(parts[1])*10e6 + int(parts[2])*10e3 + int(parts[3]) - -print('Update GitHub to point to newly signed self-hosted xpi package...') -updates_json_filepath = os.path.join(projdir, 'dist', 'mv3', 'firefox', 'updates.json') -with open(updates_json_filepath) as f: - updates_json = json.load(f) - f.close() - previous_version = updates_json['addons'][extension_id]['updates'][0]['version'] - if int_from_version(ext_version) > int_from_version(previous_version): - with open(os.path.join(projdir, 'dist', 'mv3', 'firefox', 'updates.template.json')) as f: - template_json = Template(f.read()) - f.close() - updates_json = template_json.substitute(ext_version=ext_version, tag_version=tag_version, min_browser_version=min_browser_version) - with open(updates_json_filepath, 'w') as f: - f.write(updates_json) - f.close() - # - Stage the changed file - r = subprocess.run(['git', 'status', '-s', updates_json_filepath], stdout=subprocess.PIPE) - rout = bytes.decode(r.stdout).strip() - if len(rout) >= 2 and rout[1] == 'M': - subprocess.run(['git', 'add', updates_json_filepath]) - # - Commit the staged file - r = subprocess.run(['git', 'status', '-s', updates_json_filepath], stdout=subprocess.PIPE) - rout = bytes.decode(r.stdout).strip() - if len(rout) >= 2 and rout[0] == 'M': - subprocess.run(['git', 'commit', '-m', 'Make Firefox dev build auto-update', updates_json_filepath]) - subprocess.run(['git', 'push', 'origin', 'HEAD']) - -print('All done.') diff -Nru ublock-origin-1.62.0+dfsg/dist/mv3/firefox/updates.json ublock-origin-1.67.0+dfsg/dist/mv3/firefox/updates.json --- ublock-origin-1.62.0+dfsg/dist/mv3/firefox/updates.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/dist/mv3/firefox/updates.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -{ - "addons": { - "uBOLite@raymondhill.net": { - "updates": [ - { - "version": "1.0.23.8125", - "browser_specific_settings": { "gecko": { "strict_min_version": "114.0" } }, - "update_link": "https://github.com/gorhill/uBlock/releases/download/uBOLite_1.0.23.8125/uBOLite_1.0.23.8125.firefox.signed.mv3.xpi" - } - ] - } - } -} diff -Nru ublock-origin-1.62.0+dfsg/dist/mv3/firefox/updates.template.json ublock-origin-1.67.0+dfsg/dist/mv3/firefox/updates.template.json --- ublock-origin-1.62.0+dfsg/dist/mv3/firefox/updates.template.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/dist/mv3/firefox/updates.template.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -{ - "addons": { - "uBOLite@raymondhill.net": { - "updates": [ - { - "version": "$ext_version", - "browser_specific_settings": { "gecko": { "strict_min_version": "$min_browser_version" } }, - "update_link": "https://github.com/gorhill/uBlock/releases/download/$tag_version/$tag_version.firefox.signed.mv3.xpi" - } - ] - } - } -} diff -Nru ublock-origin-1.62.0+dfsg/dist/version ublock-origin-1.67.0+dfsg/dist/version --- ublock-origin-1.62.0+dfsg/dist/version 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/dist/version 2025-10-25 19:32:51.000000000 +0000 @@ -1 +1 @@ -1.62.0 \ No newline at end of file +1.67.0 \ No newline at end of file diff -Nru ublock-origin-1.62.0+dfsg/eslint.config.mjs ublock-origin-1.67.0+dfsg/eslint.config.mjs --- ublock-origin-1.62.0+dfsg/eslint.config.mjs 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/eslint.config.mjs 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,51 @@ +import js from "@eslint/js"; +import globals from "globals"; +import json from "@eslint/json"; + +import { includeIgnoreFile } from "@eslint/compat"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const gitignorePath = path.resolve(__dirname, ".gitignore"); + +export default [ includeIgnoreFile(gitignorePath), { + files: ["**/*.js", "**/*.mjs"], + ...js.configs.recommended, +}, { + files: ["**/*.js", "**/*.mjs"], + languageOptions: { + globals: { + ...globals.browser, + browser: "readonly", + chrome: "readonly", + vAPI: "readonly", + }, + sourceType: "module", + }, + rules: { + eqeqeq: ["warn", "always"], + indent: ["error", 4, { + ignoredNodes: [ + "Program > BlockStatement", + "Program > ExpressionStatement > CallExpression > ArrowFunctionExpression > BlockStatement", + "Program > ExpressionStatement > CallExpression > FunctionExpression > BlockStatement", + "Program > IfStatement > BlockStatement", + "Program > VariableDeclaration > VariableDeclarator > CallExpression > ArrowFunctionExpression > BlockStatement", + "CallExpression > MemberExpression", + "ArrayExpression > *", + "ObjectExpression > *", + ], + }], + "no-control-regex": "off", + "no-empty": "off", + "sort-imports": "error", + "strict": "error", + }, +}, { + files: ["**/*.json"], + ignores: ["package-lock.json"], + language: "json/json", + ...json.configs.recommended, +} ]; diff -Nru ublock-origin-1.62.0+dfsg/package-lock.json ublock-origin-1.67.0+dfsg/package-lock.json --- ublock-origin-1.62.0+dfsg/package-lock.json 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/package-lock.json 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,1163 @@ +{ + "name": "uBlock", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "uBlock", + "version": "1.0.0", + "license": "GPLv3", + "devDependencies": { + "@eslint/compat": "^1.2.4", + "@eslint/js": "^9.17.0", + "@eslint/json": "^0.13.1", + "eslint": "^9.34.0", + "eslint-formatter-compact": "^8.40.0", + "globals": "^15.14.0" + }, + "engines": { + "node": ">=22", + "npm": ">=11" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/compat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.3.2.tgz", + "integrity": "sha512-jRNwzTbd6p2Rw4sZ1CgWRS8YMtqG15YyZf7zvb6gY2rB2u6n+2Z+ELW0GtL0fQgyl0pr4Y/BzBfng/BdsereRA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^8.40 || 9" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", + "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.34.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.34.0.tgz", + "integrity": "sha512-EoyvqQnBNsV1CWaEJ559rxXL4c8V92gxirbawSmVUOWXlsRxxQXl6LmCpdUblgxgSkDIqKnhzba2SjRTI/A5Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/json": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/@eslint/json/-/json-0.13.2.tgz", + "integrity": "sha512-yWLyRE18rHgHXhWigRpiyv1LDPkvWtC6oa7QHXW7YdP6gosJoq7BiLZW2yCs9U7zN7X4U3ZeOJjepA10XAOIMw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.2", + "@eslint/plugin-kit": "^0.3.5", + "@humanwhocodes/momoa": "^3.3.9", + "natural-compare": "^1.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.2", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/momoa": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/@humanwhocodes/momoa/-/momoa-3.3.9.tgz", + "integrity": "sha512-LHw6Op4bJb3/3KZgOgwflJx5zY9XOy0NU1NuyUFKGdTwHYmP+PbnQGCYQJ8NVNlulLfQish34b0VuUlLYP3AXA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.34.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.34.0.tgz", + "integrity": "sha512-RNCHRX5EwdrESy3Jc9o8ie8Bog+PeYvvSR8sDGoZxNFTvZ4dlxUB3WzQ3bQMztFrSRODGrLLj8g6OFuGY/aiQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.1", + "@eslint/core": "^0.15.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.34.0", + "@eslint/plugin-kit": "^0.3.5", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-formatter-compact": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/eslint-formatter-compact/-/eslint-formatter-compact-8.40.0.tgz", + "integrity": "sha512-cwGUs113TgmTQXecx5kfRjB7m0y2wkDLSadPTE2pK6M/wO4N8PjmUaoWOFNCP9MHgsiZwgqd5bZFnDCnszC56Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff -Nru ublock-origin-1.62.0+dfsg/package.json ublock-origin-1.67.0+dfsg/package.json --- ublock-origin-1.62.0+dfsg/package.json 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/package.json 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,32 @@ +{ + "name": "uBlock", + "version": "1.0.0", + "description": "npm dev tools", + "type": "module", + "scripts": { + "lint": "eslint --no-warn-ignored --ignore-pattern \"**/lib/\" --ignore-pattern \"**/npm/\" -- \"./src/js/*.js\" \"./src/js/**/*.js\" \"./**/*.json\" \"./platform/**/*.js\"", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/gorhill/uBlock.git" + }, + "author": "Raymond Hill", + "license": "GPLv3", + "bugs": { + "url": "https://github.com/gorhill/uBlock/issues" + }, + "homepage": "https://github.com/gorhill/uBlock#readme", + "engines": { + "node": ">=22", + "npm": ">=11" + }, + "devDependencies": { + "@eslint/compat": "^1.2.4", + "@eslint/js": "^9.17.0", + "@eslint/json": "^0.13.1", + "eslint": "^9.34.0", + "eslint-formatter-compact": "^8.40.0", + "globals": "^15.14.0" + } +} diff -Nru ublock-origin-1.62.0+dfsg/platform/browser/main.js ublock-origin-1.67.0+dfsg/platform/browser/main.js --- ublock-origin-1.62.0+dfsg/platform/browser/main.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/browser/main.js 1970-01-01 00:00:00.000000000 +0000 @@ -1,123 +0,0 @@ -/******************************************************************************* - - uBlock Origin - a browser extension to block requests. - Copyright (C) 2014-present Raymond Hill - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see {http://www.gnu.org/licenses/}. - - Home: https://github.com/gorhill/uBlock -*/ - -'use strict'; - -/******************************************************************************/ - -import publicSuffixList from './lib/publicsuffixlist/publicsuffixlist.js'; -import punycode from './lib/punycode.js'; - -import staticNetFilteringEngine from './js/static-net-filtering.js'; -import { FilteringContext } from './js/filtering-context.js'; -import { LineIterator } from './js/text-utils.js'; -import * as sfp from './js/static-filtering-parser.js'; - -import { - CompiledListReader, - CompiledListWriter -} from './js/static-filtering-io.js'; - -/******************************************************************************/ - -function compileList(rawText, writer) { - const lineIter = new LineIterator(rawText); - const parser = new sfp.AstFilterParser({ - interactive: true, - maxTokenLength: staticNetFilteringEngine.MAX_TOKEN_LENGTH, - }); - const compiler = staticNetFilteringEngine.createCompiler(); - - while ( lineIter.eot() === false ) { - let line = lineIter.next(); - - while ( line.endsWith(' \\') ) { - if ( lineIter.peek(4) !== ' ' ) { break; } - line = line.slice(0, -2).trim() + lineIter.next().trim(); - } - parser.parse(line); - - if ( parser.isFilter() === false ) { continue; } - if ( parser.isNetworkFilter() === false ) { continue; } - if ( compiler.compile(parser, writer) ) { continue; } - if ( compiler.error !== undefined ) { - console.info(JSON.stringify({ - realm: 'message', - type: 'error', - text: compiler.error - })); - } - } - - return writer.toString(); -} - -function applyList(name, raw) { - const writer = new CompiledListWriter(); - writer.properties.set('name', name); - const compiled = compileList(raw, writer); - const reader = new CompiledListReader(compiled); - staticNetFilteringEngine.fromCompiled(reader); -} - -function enableWASM(path) { - return Promise.all([ - publicSuffixList.enableWASM(`${path}/lib/publicsuffixlist`), - staticNetFilteringEngine.enableWASM(`${path}/js`), - ]); -} - -function pslInit(raw) { - if ( typeof raw !== 'string' || raw.trim() === '' ) { - console.info('Unable to populate public suffix list'); - return; - } - publicSuffixList.parse(raw, punycode.toASCII); - console.info('Public suffix list populated'); -} - -function restart(lists) { - // Remove all filters - reset(); - - if ( Array.isArray(lists) && lists.length !== 0 ) { - // Populate filtering engine with filter lists - for ( const { name, raw } of lists ) { - applyList(name, raw); - } - // Commit changes - staticNetFilteringEngine.freeze(); - staticNetFilteringEngine.optimize(); - } - - return staticNetFilteringEngine; -} - -function reset() { - staticNetFilteringEngine.reset(); -} - -export { - FilteringContext, - enableWASM, - pslInit, - restart, -}; diff -Nru ublock-origin-1.62.0+dfsg/platform/browser/test.html ublock-origin-1.67.0+dfsg/platform/browser/test.html --- ublock-origin-1.62.0+dfsg/platform/browser/test.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/browser/test.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ - - - - -uBO Static Network Filtering Engine - - - - - diff -Nru ublock-origin-1.62.0+dfsg/platform/chromium/is-webrtc-supported.html ublock-origin-1.67.0+dfsg/platform/chromium/is-webrtc-supported.html --- ublock-origin-1.62.0+dfsg/platform/chromium/is-webrtc-supported.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/chromium/is-webrtc-supported.html 2025-10-25 19:32:51.000000000 +0000 @@ -3,7 +3,7 @@ - + diff -Nru ublock-origin-1.62.0+dfsg/platform/chromium/is-webrtc-supported.js ublock-origin-1.67.0+dfsg/platform/chromium/is-webrtc-supported.js --- ublock-origin-1.62.0+dfsg/platform/chromium/is-webrtc-supported.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/chromium/is-webrtc-supported.js 2025-10-25 19:32:51.000000000 +0000 @@ -30,11 +30,9 @@ // collected. (function() { - 'use strict'; - - var pc = null; + let pc = null; try { - var PC = self.RTCPeerConnection || self.webkitRTCPeerConnection; + const PC = self.RTCPeerConnection || self.webkitRTCPeerConnection; if ( PC ) { pc = new PC(null); } diff -Nru ublock-origin-1.62.0+dfsg/platform/chromium/manifest.json ublock-origin-1.67.0+dfsg/platform/chromium/manifest.json --- ublock-origin-1.62.0+dfsg/platform/chromium/manifest.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/chromium/manifest.json 2025-10-25 19:32:51.000000000 +0000 @@ -89,7 +89,7 @@ }, "incognito": "split", "manifest_version": 2, - "minimum_chrome_version": "80.0", + "minimum_chrome_version": "93.0", "name": "uBlock Origin", "options_ui": { "page": "dashboard.html", diff -Nru ublock-origin-1.62.0+dfsg/platform/chromium/vapi-background-ext.js ublock-origin-1.67.0+dfsg/platform/chromium/vapi-background-ext.js --- ublock-origin-1.62.0+dfsg/platform/chromium/vapi-background-ext.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/chromium/vapi-background-ext.js 2025-10-25 19:32:51.000000000 +0000 @@ -26,6 +26,8 @@ // so we synthetize these missing events when this happens. // https://github.com/uBlockOrigin/uAssets/issues/10323 // Also mind whether the new tab is launched from an external application. +// https://github.com/uBlockOrigin/uBlock-issues/issues/2227 +// Revert commit related to issue above. vAPI.Tabs = class extends vAPI.Tabs { constructor() { @@ -66,8 +68,7 @@ const isClientRedirect = Array.isArray(details.transitionQualifiers) && details.transitionQualifiers.includes('client_redirect'); - const isStartPage = details.transitionType === 'start_page'; - if ( isClientRedirect === false && isStartPage === false ) { return; } + if ( isClientRedirect === false ) { return; } this.onCreatedNavigationTargetHandler({ tabId: details.tabId, sourceTabId: details.tabId, @@ -212,7 +213,7 @@ const parts = [ '(', function(details) { - if ( typeof self.uBO_scriptletsInjected === 'string' ) { return; } + if ( self.uBO_scriptletsInjected !== undefined ) { return; } const doc = document; const { location } = doc; if ( location === null ) { return; } @@ -224,7 +225,7 @@ script.appendChild(doc.createTextNode(details.scriptlets)); (doc.head || doc.documentElement).appendChild(script); self.uBO_scriptletsInjected = details.filters; - } catch (ex) { + } catch { } if ( script ) { script.remove(); diff -Nru ublock-origin-1.62.0+dfsg/platform/common/vapi-background.js ublock-origin-1.67.0+dfsg/platform/common/vapi-background.js --- ublock-origin-1.62.0+dfsg/platform/common/vapi-background.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/common/vapi-background.js 2025-10-25 19:32:51.000000000 +0000 @@ -43,15 +43,12 @@ vAPI.supportsUserStylesheets = vAPI.webextFlavor.soup.has('user_stylesheet'); -const hasOwnProperty = (o, p) => - Object.prototype.hasOwnProperty.call(o, p); - /******************************************************************************/ vAPI.app = { name: manifest.name.replace(/ dev\w+ build/, ''), version: (( ) => { - let version = manifest.version; + let version = manifest.version_name || manifest.version; const match = /(\d+\.\d+\.\d+)(?:\.(\d+))?/.exec(version); if ( match && match[2] ) { const v = parseInt(match[2], 10); @@ -190,7 +187,7 @@ set: function(details) { for ( const setting in details ) { - if ( hasOwnProperty(details, setting) === false ) { continue; } + if ( Object.hasOwn(details, setting) === false ) { continue; } switch ( setting ) { case 'prefetching': { const enabled = !!details[setting]; @@ -320,7 +317,7 @@ try { result = await webext.tabs.executeScript(...args); } - catch(reason) { + catch { } return Array.isArray(result) ? result : []; } @@ -334,7 +331,7 @@ try { tab = await webext.tabs.get(tabId); } - catch(reason) { + catch { } return tab instanceof Object ? tab : null; } @@ -351,7 +348,7 @@ try { await webext.tabs.insertCSS(...arguments); } - catch(reason) { + catch { } } @@ -360,7 +357,7 @@ try { tabs = await webext.tabs.query(queryInfo); } - catch(reason) { + catch { } return Array.isArray(tabs) ? tabs : []; } @@ -372,7 +369,7 @@ try { await webext.tabs.removeCSS(...arguments); } - catch(reason) { + catch { } } @@ -530,7 +527,7 @@ try { tab = await webext.tabs.update(...arguments); } - catch (reason) { + catch { } return tab instanceof Object ? tab : null; } @@ -556,7 +553,7 @@ try { await webext.tabs.remove(tabId); } - catch (reason) { + catch { } } @@ -569,7 +566,7 @@ { bypassCache: bypassCache === true } ); } - catch (reason) { + catch { } } @@ -668,7 +665,7 @@ try { win = await webext.windows.get(...arguments); } - catch (reason) { + catch { } return win instanceof Object ? win : null; }, @@ -677,7 +674,7 @@ try { win = await webext.windows.create(...arguments); } - catch (reason) { + catch { } return win instanceof Object ? win : null; }, @@ -686,7 +683,7 @@ try { win = await webext.windows.update(...arguments); } - catch (reason) { + catch { } return win instanceof Object ? win : null; }, @@ -702,7 +699,7 @@ try { await webext.browserAction.setTitle(...arguments); } - catch (reason) { + catch { } }, }; @@ -712,28 +709,28 @@ try { await webext.browserAction.setBadgeTextColor(...arguments); } - catch (reason) { + catch { } }; vAPI.browserAction.setBadgeBackgroundColor = async function() { try { await webext.browserAction.setBadgeBackgroundColor(...arguments); } - catch (reason) { + catch { } }; vAPI.browserAction.setBadgeText = async function() { try { await webext.browserAction.setBadgeText(...arguments); } - catch (reason) { + catch { } }; vAPI.browserAction.setIcon = async function() { try { await webext.browserAction.setIcon(...arguments); } - catch (reason) { + catch { } }; } @@ -807,7 +804,7 @@ let data; try { data = ctx.getImageData(0, 0, w, h); - } catch(ex) { + } catch { } return data; }; @@ -1084,7 +1081,7 @@ msgId: this.msgId, msg: response !== undefined ? response : null, }); - } catch (ex) { + } catch { this.messaging.onPortDisconnect(this.port); } // Store for reuse @@ -1220,7 +1217,7 @@ { const wrrt = browser.webRequest.ResourceType; for ( const typeKey in wrrt ) { - if ( hasOwnProperty(wrrt, typeKey) ) { + if ( Object.hasOwn(wrrt, typeKey) ) { this.validTypes.add(wrrt[typeKey]); } } @@ -1473,7 +1470,7 @@ let store; try { store = await webext.storage.managed.get(); - } catch(ex) { + } catch { } vAPI.storage.set({ cachedManagedStorage: store || {} }); }; @@ -1488,7 +1485,7 @@ } else { bin = bin.cachedManagedStorage; } - } catch(ex) { + } catch { bin = {}; } cacheManagedStorage(); @@ -1688,7 +1685,7 @@ // operation to fail. try { await deleteChunks(datakey, chunkCount + 1); - } catch (reason) { + } catch { } // Push the data to browser-provided cloud storage. @@ -1742,7 +1739,7 @@ if ( typeof entry === 'string' ) { entry = JSON.parse(entry); } - } catch(_) { + } catch { } return entry; }; @@ -1763,7 +1760,7 @@ webext.storage.sync.getBytesInUse(keys), webext.storage.sync.getBytesInUse(null), ]); - } catch(ex) { + } catch { } if ( Array.isArray(results) === false ) { return; } return { used: results[0], total: results[1], max: QUOTA_BYTES }; diff -Nru ublock-origin-1.62.0+dfsg/platform/common/vapi-client.js ublock-origin-1.67.0+dfsg/platform/common/vapi-client.js --- ublock-origin-1.62.0+dfsg/platform/common/vapi-client.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/common/vapi-client.js 2025-10-25 19:32:51.000000000 +0000 @@ -165,7 +165,7 @@ } try { this.port = browser.runtime.connect({name: vAPI.sessionId}) || null; - } catch (ex) { + } catch { this.port = null; } // Not having a valid port at this point means the main process is diff -Nru ublock-origin-1.62.0+dfsg/platform/common/vapi-common.js ublock-origin-1.67.0+dfsg/platform/common/vapi-common.js --- ublock-origin-1.62.0+dfsg/platform/common/vapi-common.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/common/vapi-common.js 2025-10-25 19:32:51.000000000 +0000 @@ -166,7 +166,9 @@ soup.add('ipaddress'); // Whether this is a dev build. - if ( /^\d+\.\d+\.\d+\D/.test(browser.runtime.getManifest().version) ) { + const manifest = browser.runtime.getManifest(); + const version = manifest.version_name || manifest.version; + if ( /^\d+\.\d+\.\d+\D/.test(version) ) { soup.add('devbuild'); } @@ -178,8 +180,11 @@ soup.add('native_css_has'); } + const extensionOrigin = browser.runtime.getURL(''); + // Order of tests is important - if ( browser.runtime.getURL('').startsWith('moz-extension://') ) { + flavor.isGecko = extensionOrigin.startsWith('moz-extension://'); + if ( flavor.isGecko ) { soup.add('firefox') .add('user_stylesheet') .add('html_filtering'); diff -Nru ublock-origin-1.62.0+dfsg/platform/dig/snfe.js ublock-origin-1.67.0+dfsg/platform/dig/snfe.js --- ublock-origin-1.62.0+dfsg/platform/dig/snfe.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/dig/snfe.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,22 +19,12 @@ Home: https://github.com/gorhill/uBlock */ -/* eslint-disable-next-line no-redeclare */ /* globals process */ -'use strict'; - -/******************************************************************************/ - -import { strict as assert } from 'assert'; +import { StaticNetFilteringEngine, enableWASM } from './index.js'; +import { mkdir, readFile, writeFile } from 'fs/promises'; import { createRequire } from 'module'; -import { readFile, writeFile, mkdir } from 'fs/promises'; import { dirname } from 'path'; -import { fileURLToPath } from 'url'; - -const __dirname = dirname(fileURLToPath(import.meta.url)); - -import { enableWASM, StaticNetFilteringEngine } from './index.js'; /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/platform/firefox/manifest.json ublock-origin-1.67.0+dfsg/platform/firefox/manifest.json --- ublock-origin-1.62.0+dfsg/platform/firefox/manifest.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/firefox/manifest.json 2025-10-25 19:32:51.000000000 +0000 @@ -17,10 +17,10 @@ "browser_specific_settings": { "gecko": { "id": "uBlock0@raymondhill.net", - "strict_min_version": "78.0" + "strict_min_version": "92.0" }, "gecko_android": { - "strict_min_version": "79.0" + "strict_min_version": "92.0" } }, "commands": { diff -Nru ublock-origin-1.62.0+dfsg/platform/firefox/vapi-background-ext.js ublock-origin-1.67.0+dfsg/platform/firefox/vapi-background-ext.js --- ublock-origin-1.62.0+dfsg/platform/firefox/vapi-background-ext.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/firefox/vapi-background-ext.js 2025-10-25 19:32:51.000000000 +0000 @@ -287,7 +287,7 @@ if ( domainFromHostname(cn) === domainFromHostname(hn) ) { return; } } if ( this.cnameIgnoreList !== null ) { - if ( this.cnameIgnoreList.test(cn) === false ) { return; } + if ( this.cnameIgnoreList.test(cn) ) { return; } } if ( this.cnameIgnoreRootDocument ) { const origin = hostnameFromNetworkURL(details.documentUrl || details.url); @@ -355,7 +355,7 @@ const parts = [ '(', function(details) { - if ( typeof self.uBO_scriptletsInjected === 'string' ) { return; } + if ( self.uBO_scriptletsInjected !== undefined ) { return; } const doc = document; const { location } = doc; if ( location === null ) { return; } @@ -373,7 +373,7 @@ script = doc.createElement('script'); script.appendChild(doc.createTextNode(code)); (doc.head || doc.documentElement).appendChild(script); - } catch (ex) { + } catch { } if ( script ) { script.remove(); @@ -400,7 +400,7 @@ script.src = url; (doc.head || doc.documentElement || doc).append(script); self.uBO_scriptletsInjected = details.filters; - } catch (ex) { + } catch { } if ( url ) { if ( script ) { script.remove(); } diff -Nru ublock-origin-1.62.0+dfsg/platform/firefox/webext.js ublock-origin-1.67.0+dfsg/platform/firefox/webext.js --- ublock-origin-1.62.0+dfsg/platform/firefox/webext.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/firefox/webext.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,4 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - export default browser; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/README.md ublock-origin-1.67.0+dfsg/platform/mv3/README.md --- ublock-origin-1.62.0+dfsg/platform/mv3/README.md 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/README.md 2025-10-25 19:32:51.000000000 +0000 @@ -7,17 +7,21 @@ 1. Open Bash console 2. `git clone https://github.com/gorhill/uBlock.git` 3. `cd uBlock` -4. `make mv3-[platform]`, where `[platform]` is either `chromium` or `firefox` -5. This will fully build uBO Lite, and during the process filter lists will be downloaded from their respective remote servers +4. `git submodule init` +5. `git submodule update` +6. `make mv3-[platform]`, where `[platform]` is either `chromium`, `edge`, `firefox`, or `safari` +7. This will fully build uBO Lite, and during the process filter lists will be downloaded from their respective remote servers Upon completion of the script, the resulting extension package will become present in: - Chromium: `dist/build/uBOLite.chromium` -- Firefox: `dist/build/uBOLite.firefox` +- Edge: `dist/build/uBOLite.edge` +- Firefox: `dist/build/uBOLite.firefox` +- Safari: `dist/build/uBOLite.safari` The folder `dist/build/mv3-data` will cache data fetched from remote servers, so as to avoid fetching repeatedly from remote servers with repeated build commands. Use `make cleanassets` to remove all locally cached filter lists if you want to build with latest versions of filter lists. -The file `dist/build/mv3-data/log.txt` will contain information about what happened during the build process. +The file `dist/build/uBOLite.[platform]/log.txt` will contain information about what happened during the build process. The entry in the `Makefile` which implement the build process is `tools/make-mv3.sh [platform]`.[1] This Bash script copy various files from uBlock Origin branch and MV3-specific branch into a single folder which will be the final extension package. @@ -27,5 +31,4 @@ --- -[1] https://github.com/gorhill/uBlock/blob/c4d324362fdb95ff8ef20f0b18f42f0eec955433/tools/make-mv3.sh -[2] https://github.com/gorhill/uBlock/blob/c4d324362fdb95ff8ef20f0b18f42f0eec955433/tools/make-mv3.sh#L103 +[1] https://github.com/gorhill/uBlock/blob/c4d324362fdb95ff8ef20f0b18f42f0eec955433/tools/make-mv3.sh
diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/chromium/manifest.json ublock-origin-1.67.0+dfsg/platform/mv3/chromium/manifest.json --- ublock-origin-1.62.0+dfsg/platform/mv3/chromium/manifest.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/chromium/manifest.json 2025-10-25 19:32:51.000000000 +0000 @@ -12,12 +12,24 @@ "service_worker": "/js/background.js", "type": "module" }, + "commands": { + "enter-zapper-mode": { + "description": "__MSG_zapperTipEnter__" + }, + "enter-picker-mode": { + "description": "__MSG_pickerTipEnter__" + } + }, "declarative_net_request": { "rule_resources": [ ] }, "default_locale": "en", "description": "__MSG_extShortDesc__", + "host_permissions": [ + "" + ], + "incognito": "split", "icons": { "16": "img/icon_16.png", "32": "img/icon_32.png", @@ -28,9 +40,6 @@ "minimum_chrome_version": "122.0", "name": "__MSG_extName__", "options_page": "dashboard.html", - "optional_host_permissions": [ - "" - ], "permissions": [ "activeTab", "declarativeNetRequest", @@ -49,6 +58,33 @@ ], "matches": [ "" + ], + "use_dynamic_url": true + }, + { + "resources": [ + "/zapper-ui.html" + ], + "matches": [ + "" + ], + "use_dynamic_url": true + }, + { + "resources": [ + "/picker-ui.html" + ], + "matches": [ + "" + ], + "use_dynamic_url": true + }, + { + "resources": [ + "/unpicker-ui.html" + ], + "matches": [ + "" ], "use_dynamic_url": true } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/en.md ublock-origin-1.67.0+dfsg/platform/mv3/description/en.md --- ublock-origin-1.62.0+dfsg/platform/mv3/description/en.md 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/en.md 2025-10-25 19:32:51.000000000 +0000 @@ -1,30 +1,9 @@ ## Description -**uBO Lite** (uBOL), a **permission-less** [MV3 API-based](https://developer.chrome.com/docs/extensions/mv3/intro/) content blocker. +**uBO Lite** (uBOL), an efficient [MV3 API-based](https://developer.chrome.com/docs/extensions/mv3/intro/) content blocker. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is [performed reliably](https://developer.chrome.com/docs/extensions/reference/scripting/#method-registerContentScripts) by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. -uBOL does not require broad "read/modify data" [permission](https://developer.chrome.com/docs/extensions/mv3/declare_permissions/) at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read/modify data" permissions at install time.
**However, [...]** - uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using declarative cosmetic and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -![uBOL's popup panel: no permission](https://user-images.githubusercontent.com/585534/195468156-d7e63ab9-abfa-443c-a8f6-e646a29b801e.png) - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request: - -![uBOL's popup panel: browser warning](https://user-images.githubusercontent.com/585534/195342593-2b82b740-70a3-4507-a0e5-d7aee803b286.png) - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site: - -![uBOL's popup panel: permissions to inject content](https://user-images.githubusercontent.com/585534/195342612-85d109d9-9006-4eb5-95a5-fec8a4f233ea.png) - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to modify and read data on all websites: - -![uBOL's options: Default filtering mode](https://user-images.githubusercontent.com/585534/195343335-a0aa103e-621e-4137-9bcf-9821dc881be1.png) - -
- The default ruleset corresponds to at least uBlock Origin's default filterset: - uBlock Origin's built-in filter lists @@ -33,9 +12,3 @@ - Peter Lowe’s Ad and tracking server list You can add more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ar.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ar.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ar.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ar.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -نسخة مبسطة (uBOL) مانع محتوى من نوع MV3 تجريبي *أقل طلبا للتصاريح* MV3-قاعدة الحظر الأساسية +uBO Lite (uBOL) هو مانع محتوى يعتمد على MV3. تتوافق مجموعة القواعد الافتراضية مع مجموعة عوامل التصفية الافتراضية لـ uBlock Origin: @@ -9,28 +9,4 @@ يمكنك تفعيل المزيد من مجموعات القواعد من خلال زيارة صفحة الخيارات - انقر على أيقونة _الترس_ في لوحة الإشعارات. -uBOL صريح تمامًا، مما يعني أنه لا تحتاج إلى uBOL بشكل دائم لحدوث تصفية المحتوى، يتم إجراء تصفية المحتوى من خلال إضافة CSS/JS بشكل موثوق به بواسطة المتصفح نفسه بدلًا من الإضافة. - هذا يعني أن uBOL نفسه لا يستهلك موارد وحدة المعالجة المركزية/الذاكرة أثناء استمراره في حظر المحتوى. عملية عامل الخدمة في uBOL مطلوبة _فقط_ عند التفاعل مع اللوحة المنبثقة أو صفحة الخيارات. - -لا يتطلب uBOL صلاحية واسعة «لقراءة البيانات وتعديلها» في وقت التثبيت، وبالتالي فإن قدراته محدودة مقارنة بـ uBlock Origin أو إضافات حظر الإعلانات الأخرى التي تتطلب صلاحية واسعة «قراءة البيانات وتعديلها» في وقت التثبيت. - - -ومع ذلك، يسمح لك uBOL "بوضوح" بمنح صلاحيات موسعة على مواقع محددة من اختيارك حتى يتمكن من التصفية بشكل أفضل على تلك المواقع باستخدام التصفية التجميلية وإضافة النص. - - -لمنح صلاحيات موسعة على موقع معين، افتح اللوحة المنبثقة واختر وضع التصفية إما الأمثل أو الكامل. - -سيحذرك المتصفح من مخاطر منح صلاحيات إضافية التي يطلبها الامتداد على الموقع الحالي، وسيتعين عليك إختيار بما إذا كنت تقبل الطلب أو ترفضه. - - -إذا قبلت طلب uBOL بالحصول على صلاحيات إضافية على الموقع الحالي، فستتمكن من تصفية المحتوى بشكل أفضل للموقع الحالي. - - -بإمكانك اختيار وضع التصفية الافتراضية من خلال صفحة خيارات uBOL. إذا اخترت الوضع الأمثل أو الكامل باعتباره الوضع الافتراضي، فستحتاج إلى منح uBOL الإذن لقراءة البيانات وتعديلها على جميع مواقع الويب. - - -ضع في اعتبارك أن هذا لا يزال عملًا قيد التنفيذ، هذه هي الأهداف النهائية: - -لا يمكنك تحديد الأذونات المستخدمة لاحقًا في التثبيت، تحديدك للأذونات سيكون خلال زيارتك لكل موقع. - -تقريري تمامًا للموثوقية ولكفاءة وحدة المعالجة المركزية/الذاكرة. +uBOL صريح تمامًا، مما يعني أنه لا تحتاج إلى uBOL بشكل دائم لحدوث تصفية المحتوى، يتم إجراء تصفية المحتوى من خلال إضافة CSS/JS بشكل موثوق به بواسطة المتصفح نفسه بدلًا من الإضافة. هذا يعني أن uBOL نفسه لا يستهلك موارد وحدة المعالجة المركزية/الذاكرة أثناء استمراره في حظر المحتوى. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.az.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.az.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.az.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.az.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) *icazəsiz* MV3 əsaslı məzmun bloklayıcısıdır. +uBO Lite (uBOL) is an MV3-based content blocker. Defolt qaydalar dəsti uBlock Origin-in defolt filtr dəstinə uyğundur: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.be.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.be.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.be.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.be.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,30 +1,12 @@ -uBO Лайт (uBOL) гэта блакіроўшчык кантэнту з меншымі патрабаваннямі да дазволаў заснаваны на MV3 +uBO Lite (uBOL) гэта базаваны на MV3 блакавальнік змесціва. Прадвызначаны набор правіл адпавядае тыпавому набору фільтраў uBlock Origin: - Убудаваныя спісы фільтраў uBlock Origin - EasyList - EasyPrivacy -- Спіс сервераў рэкламы ды адсочвання ад Peter Lowe +- Спіс сервераў з рэкламай і адсочвання ад Peter Lowe -You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. +Вы можаце ўключыць больш набораў правіл праз старонку налад -- націсніце на значок _Шасцярэнькі_ на ўсплывальнай панэлі. -uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Цалкам дэкларатыўная ацэнка надзейнасці і эфектыўнасці работы працэсара/памяці. +uBOL цалкам дэкларатыўны, то-бок не мае неабходнасці ў сталым uBOL працэсе дзеля фільтрацыі, а фільтрацыя змесціва на аснове інʼекцыі CSS/JS надзейна выконваецца пераважна самім браўзерам замест пашырэння. Гэта значыць, што uBOL не спажывае рэсурсаў працэсара/памяці пры блакаванні зместу -- службовы працэс uBOL патрэбны _толькі_ падчас узаемадзеяння з усплывальнай панэллю або наладамі. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.bg.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.bg.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.bg.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.bg.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) е блокер за съдържание *без разрешения*, базиран на MV3. +uBO Lite (uBOL) е блокер за съдържание, базиран на MV3. Наборът от правила по подразбиране съответства на набора от филтри по подразбиране на uBlock Origin: @@ -10,21 +10,3 @@ Можете да включите още набори от правила, като посетите страницата с опции – щракнете върху иконата „зъбно колело“ в изскачащия панел. uBOL е изцяло декларативен, което означава, че няма нужда от постоянен процес на uBOL за филтриране, а филтрирането на съдържание, базирано на инжектиране на CSS/JS, се извършва надеждно от самия браузър, а не от разширението. Това означава, че самият uBOL не консумира ресурси на процесора/паметта, докато тече блокирането на съдържанието – работният процес на услугата на uBOL е необходим _само_ когато взаимодействате с изскачащия панел или страниците с опции. - -uBOL не изисква широко разрешение за "четене и промяна на данни" по време на инсталиране, поради което възможностите му са ограничени в сравнение с uBlock Origin или други блокери на съдържание, изискващи широко разрешение за "четене и промяна на данни" по време на инсталиране. - -Въпреки това uBOL ви позволява да предоставите *изрично* разширени разрешения за определени сайтове по ваш избор, за да може да филтрира по-добре тези сайтове, като използва козметично филтриране и инжектиране на скриптове. - -За да предоставите разширени разрешения за даден сайт, отворете изскачащия панел и изберете по-висок режим на филтриране, например Оптимален или Пълен. - -След това браузърът ще ви предупреди за последиците от предоставянето на допълнителните разрешения, поискани от разширението, за текущия сайт и ще трябва да кажете на браузъра дали приемате или отхвърляте искането. - -Ако приемете искането на uBOL за допълнителни разрешения за текущия сайт, той ще може да филтрира по-добре съдържанието на текущия сайт. - -Можете да зададете режима на филтриране по подразбиране от страницата с опции на uBOL. Ако изберете оптимален или пълен режим по подразбиране, ще трябва да предоставите на uBOL разрешение за четене и промяна на данни във всички уебсайтове. - -Имайте предвид, че това все още е в процес на разработка с тези крайни цели: - -- По време на инсталацията няма широки разрешения за хоста – разширените разрешения се предоставят изрично от потребителя за всеки сайт. - -- Изцяло декларативен за надеждност и ефективност на процесора/паметта. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.bn.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.bn.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.bn.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.bn.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) হল একটি *অনুমতি-হীন* MV3-ভিত্তিক কন্টেন্ট ব্লকার। +uBO Lite (uBOL) হলো একটি ম্যানিফেস্ট ভার্সন ৩ ভিত্তিক কনটেন্ট ব্লকার পূর্ব নির্ধারিত নিয়ম সেট uBlock অরিজিনের ডিফল্ট ফিল্টারসেটের সাথে মিলে যায়: @@ -7,24 +7,6 @@ - সহজ গোপনীয়তা - পিটার লো এর বিজ্ঞাপন এবং ট্র্যাকিং সার্ভার তালিকা -You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. +তুমি অপশন পাতায় গিয়ে আরও নিয়ম যোগ করতে পারো -- পপআপ প্যানেলে _গিয়ার_ আইকনে ক্লিক করে। uBOL সম্পূর্ণরূপে ঘোষণামূলক, অর্থাৎ ফিল্টারিং করতে একটি স্থায়ী uBOL প্রক্রিয়ার প্রয়োজন নেই, এবং CSS/JS ইনজেকশন-ভিত্তিক বিষয়বস্তু ফিল্টারিং এক্সটেনশনের পরিবর্তে ব্রাউজার নিজেই নির্ভরযোগ্যভাবে এই কাজ করে থাকে। এর মানে হল যে কন্টেন্ট ব্লকিং চলমান থাকা অবস্থায় uBOL নিজেই CPU/মেমরি রিসোর্স ব্যবহার করে না -- uBOL-এর পরিষেবার প্রক্রিয়ার প্রয়োজন শুধুমাত্র_ যখন আপনি পপআপ প্যানেল বা অপশন পেজগুলির সাথে ইন্টারঅ্যাক্ট করেন। - -uBOL-এর ইন্সটল করার সময় বিস্তৃত "পড়ার ও ডেটা পরিবর্তন করার" অনুমতির প্রয়োজন হয় না, তাই ইউব্লক অরিজিন বা অন্যান্য কনটেন্ট ব্লকের তুলনায় এটির সীমিত ক্ষমতা বাক্সের বাইরে রয়েছে যার জন্য ইন্সটল করার সময় বিস্তৃত "ডেটা পড়ুন এবং পরিবর্তন করুন" অনুমতি প্রয়োজন। - -যাইহোক, uBOL আপনাকে আপনার পছন্দের নির্দিষ্ট সাইটে *স্পষ্টভাবে* বর্ধিত অনুমতি প্রদান করে যাতে এটি কসমেটিক ফিল্টারিং এবং স্ক্রিপ্টলেট ইনজেকশন ব্যবহার করে সেই সাইটগুলিতে আরও ভাল ফিল্টার করতে পারে। - -একটি সাইটে বর্ধিত অনুমতি প্রদানের জন্য, পপআপ প্যানেল খুলুন এবং একটি উচ্চতর ফিল্টারিং মোড বাছাই করুন যেমন অপটিমাল বা কমপ্লিট। - -ব্রাউজারটি তখন বর্তমান সাইটে এক্সটেনশন দ্বারা অনুরোধ করা অতিরিক্ত অনুমতি প্রদানের প্রভাব সম্পর্কে আপনাকে সতর্ক করবে এবং আপনি অনুরোধটি গ্রহণ করবেন বা প্রত্যাখ্যান করবেন কিনা তা আপনার ব্রাউজারকে বলতে হবে। - -আপনি যদি বর্তমান সাইটে অতিরিক্ত অনুমতির জন্য uBOL-এর অনুরোধ গ্রহণ করেন, তাহলে এটি বর্তমান সাইটের জন্য আরও ভালভাবে ফিল্টার করতে সক্ষম হবে। - -আপনি uBOL এর বিকল্প পৃষ্ঠা থেকে ডিফল্ট ফিল্টারিং মোড সেট করতে পারেন। আপনি যদি অপটিমাল বা কমপ্লিট মোডটিকে ডিফল্ট হিসেবে বেছে নেন, তাহলে আপনাকে uBOL-কে সমস্ত ওয়েবসাইটের ডেটা পড়তে এবং পরিবর্তন করার অনুমতি দিতে হবে। - -মনে রাখবেন এই শেষ লক্ষ্যগুলির ফলাফলের সাথে এখনও সংস্করণ কাজ চলছে: - -- ইনস্টল করার সময় কোনও বিস্তৃত অনুমতি নেই -- বর্ধিত অনুমতিগুলি প্রতি-সাইট ভিত্তিতে ব্যবহারকারীর দ্বারা স্পষ্টভাবে প্র্রদান করা হয়। - -- নির্ভরযোগ্যতা এবং CPU/মেমরি দক্ষতার জন্য সম্পূর্ণরূপে পূর্বঘোষণামুূলক। diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.br_FR.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.br_FR.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.br_FR.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.br_FR.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,30 +1,12 @@ -uBO Lite (uBOL) zo ur stanker noazadurioù *hep aotre rekis ebet* diazezet war ar manifesto MV3. +uBO Lite (uBOL) zo ur stanker noazadurioù diazezet war ar manifesto MV3. Ar reolennoù dre ziouer a glot gant silañ dre ziouer uBlock Origin: - Rolloù siloù genidik a uBlock Origin - EasyList - EasyPrivacy -- Roll bruderezh ha servijerioù heuliañ Peter Lowe +- Roll ar servijerioù brudañ ha heuliañ eus Peter Lowe -You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. +Tu zo deoc'h ouzhpennañ reolennoù all en arventennoù -- klikit war an ikon _kendentadur_ er banell popup. Disklêriañ a ra uBOL penn-da-benn, da lavaret eo n'eus ket ezhomm eus un argerzh uBOL padus evit ma c'hoarvezfe ar silañ, ha silañ endalc'hadoù diazezet war enlakaat CSS/JS a vez graet en un doare fizius gant ar merdeer e-unan kentoc'h eget gant an astenn. Kement-se a dalvez ne vez ket gounezet gant uBOL e-unan arc'hwelioù CPU/memor e-pad ma vez stanket an endalc'hadoù -- ezhomm zo eus argerzh al labourer servij uBOL _nemet_ pa vez etregweredet gant ar banell digeriñ pe ar pajennoù dibarzhioù. - -UBOL n'en deus ket ezhomm eus aotreoù ledan "lenn ha kemmañ roadennoù" e-pad ar staliañ, setu perak e c'halloudoù bevennet e-keñver uBlock Origin pe stankerien endalc'hadoù all a c'houlenn aotreoù ledan "lenn ha kemmañ roadennoù" e-pad ar staliañ. - -Koulskoude ez eus tu deoc'h reiñ *sklaer* aotreoù ouzhpenn da uBOL el lec'hiennoù ma fell deoc'h, mod-se e vint silet gwelloc'h en ur implij siloù kened hag ensinkladurioù scriplet. - -Evit reiñ aotreoù ouzhpenn da uBOL en ul lec'hienn bennak, n'ho peus nemet digeriñ ar prenestr pop-up ha diuzañ ul live silañ uheloc'h evel ar mod Gwellañ pe ar mod Klok - -Goude-se e vo kelaouet ac'hanoc'h gant ar merdeer diwar-benn efedoù reiñ an aotreoù ouzhpenn goulennet gant an astenn war al lec'hienn bremanel, ha ret e vo deoc'h lâret d'ar merdeer hag-eñ e vo degemeret pe nac'het ar goulenn ganeoc'h. - -Ma asantit da reiñ muioc'h a aotreoù da uBOL war ar bajenn-mañ e vo silet gwelloc'h. - -Gallout a rit termeniñ ar mod silañ dre ziouer e pajenn arventennoù uBOL. Ma tibabit ar mod Gwellañ pe an hini Klok evel ar mod dre ziouer e vo ret deoc'h aotren uBOL da lenn ha kemmañ roadennoù en holl lec'hiennoù. - -Dalc'hit soñj ez eo uBOL ur raktres war ober c'hoazh hag a zo e bal: - -- Aotreoù ostiz ledan ebet e-pad ar staliañ -- aotreoù astennet a vez roet splann gant an implijer dre lec'hienn. - -- Disklêriañ penn-da-benn evit ar fiziañs hag an efedusted CPU/memor. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.bs.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.bs.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.bs.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.bs.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,30 +1,12 @@ -uBO Lite (uBOL) je blokator sadržaja zasnovan na MV3 *bez dozvole*. +uBO Lite (uBOL) je blokator sadržaja baziran na MV3. Zadani skup pravila odgovara zadanom skupu filtera uBlock Origin: - UBlock Origin ugrađene liste filtera - EasyList - EasyPrivacy -- Oglas Peter Lowe i lista servera za praćenje +- Peter Lowe-ova lista servera za oglase i praćenje -You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. +Možete omogućiti više skupova pravila posjetom stranice s opcijama -- kliknite na ikonu _Cogs_ u skočnom panelu. uBOL je potpuno deklarativno, što znači da nema potrebe za trajnim uBOL procesom da bi se filtriranje dogodilo, a filtriranje sadržaja zasnovano na CSS/JS injekcijama se pouzdano izvodi od strane samog pretraživača, a ne ekstenzije. To znači da sam uBOL ne troši CPU/memorijske resurse dok je blokiranje sadržaja u toku -- proces uBOL-a servisnog radnika je potreban _samo_ kada stupite u interakciju sa iskačućim panelom ili stranicama sa opcijama. - -uBOL ne zahtijeva široku dozvolu za "čitanje i modificiranje podataka" u vrijeme instalacije, stoga su njegove ograničene mogućnosti izvan kutije u poređenju sa uBlock Origin-om ili drugim blokatorima sadržaja koji zahtijevaju široke dozvole za "čitanje i modificiranje podataka" u vrijeme instalacije. - -Međutim, uBOL vam omogućava da *eksplicitno* dodijelite proširene dozvole na određenim web lokacijama po vašem izboru kako bi mogao bolje filtrirati te stranice koristeći kozmetičko filtriranje i injekcije skriptleta. - -Da biste dali proširene dozvole za datu web lokaciju, otvorite iskačući panel i odaberite viši način filtriranja kao što je Optimal ili Complete. - -Pregledač će vas tada upozoriti na efekte odobravanja dodatnih dozvola koje ekstenzija traži na trenutnoj web stranici, a vi ćete morati reći pretraživaču da li prihvatate ili odbijate zahtjev. - -Ako prihvatite uBOL-ov zahtjev za dodatnim dozvolama na trenutnoj stranici, moći će bolje filtrirati sadržaj za trenutnu stranicu. - -Možete postaviti zadani način filtriranja sa uBOL-ove stranice sa opcijama. Ako odaberete Optimal ili Kompletan način kao zadani, morat ćete dati uBOL-u dozvolu da čita i mijenja podatke na svim web stranicama. - -Imajte na umu da je ovo još uvijek u toku, sa ovim krajnjim ciljevima: - -- Nema širokih dozvola za host u vrijeme instalacije - proširene dozvole se eksplicitno dodeljuju od strane korisnika na bazi po lokaciji. - -- Potpuno deklarativno za pouzdanost i efikasnost CPU/memorije. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ca.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ca.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ca.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ca.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -L'uBO Lite (uBOL) és un blocador de contingut *sense permisos* basat en MV3. +L'uBO Lite (uBOL) és un blocador de contingut basat en MV3. El conjunt de regles per defecte correspon al conjunt de filtres per defecte d'uBlock Origin: @@ -12,21 +12,3 @@ L'uBOL és totalment declaratiu, és a dir, no cal un procés uBOL permanent perquè es produeixi el filtratge, i el filtratge de contingut basat en injecció CSS/JS es realitza de manera fiable pel propi navegador més que per l'extensió. Això vol dir que l'uBOL en si no consumeix recursos de CPU/memòria mentre el bloqueig de contingut està en curs; el procés de treballador de servei d'uBOL només es requereix quan interactueu amb el tauler emergent o les pàgines d'opcions. - -L'uBOL no requereix un ampli permís de "lectura i modificació de dades" en el moment de la instal·lació, per tant, les seves capacitats limitades en comparació amb l'uBlock Origin o altres blocadors de contingut que requereixen amplis permisos de "lectura i modificació de dades" en el moment de la instal·lació. - -Tanmateix, l'uBOL us permet concedir *explícitament* permisos ampliats en llocs específics que trieu perquè pugui filtrar millor en aquests llocs mitjançant filtres cosmètics i injeccions de scriptlet. - -Per concedir permisos ampliats en un lloc determinat, obriu el tauler emergent i seleccioneu un mode de filtrat superior, com ara Òptim o Complet. - -Aleshores, el navegador us avisarà sobre els efectes de la concessió dels permisos addicionals sol·licitats per l'extensió al lloc actual, i haureu d'indicar-li al navegador si accepteu o rebutgeu la sol·licitud. - -Si accepteu la sol·licitud d'uBOL de permisos addicionals al lloc actual, podrà filtrar millor el contingut del lloc actual. - -Podeu establir el mode de filtratge per defecte des de la pàgina d'opcions d'uBOL. Si trieu el mode Òptim o Complet per defecte, haureu de concedir a l'uBOL el permís per llegir i modificar dades a tots els llocs web. - -Tingueu en compte que encara és un treball en curs, amb aquests objectius finals: - -- No hi ha permisos d'amfitrió amplis en el moment de la instal·lació; els permisos ampliats els concedeix explícitament l'usuari per lloc. - -- Totalment declaratiu per a la fiabilitat i l'eficiència de la CPU/memòria. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.cs.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.cs.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.cs.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.cs.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) je blokovač obsahu vyžadující méně oprávnění, založený na MV3. +uBO Lite (uBOL) je blokovač obsahu založený na MV3. Výchozí sada pravidel koresponduje k výchozím sadám filtrů uBlock Origin: @@ -10,21 +10,3 @@ Další sady pravidel můžete povolit na stránce nastavení - klikněte na ikonu _Ozubeného kolečka_ ve vyskakovacím panelu. uBOL je zcela deklarativní, což znamená, že pro filtrování není potřeba permanentní proces uBOL a filtrování obsahu založené na vstřikování CSS/JS je spolehlivě prováděno samotným prohlížečem, nikoli rozšířením. To znamená, že samotný uBOL nespotřebovává zdroje CPU/paměti, zatímco probíhá blokování obsahu – proces servisního pracovníka uBOL je vyžadován _pouze_ při interakci s vyskakovacím panelem nebo stránkami nastavení. - -uBOL nevyžaduje rozsáhlá oprávnění ke "čtení a úpravě dat" v době instalace, a proto má ihned po instalaci omezené možnosti ve srovnání s uBlock Origin nebo jinými blokovači obsahu, které vyžadují rozsáhlá oprávnění ke "čtení a úpravě dat" v době instalace. - -Nicméně, uBOL vám umožňuje *explicitně* udělit rozšířená oprávnění na konkrétních webech podle vašeho výběru, aby mohl na těchto webech lépe filtrovat pomocí kosmetického filtrování a vstřikování skriptů. - -Chcete-li na daném webu udělit rozšířená oprávnění, otevřete vyskakovací panel a vyberte vyšší režim filtrování, například optimální nebo kompletní. - -Prohlížeč vás poté upozorní na důsledky udělení dalších oprávnění požadovaných rozšířením na aktuálním webu a vy budete muset prohlížeči sdělit, zda žádost přijímáte nebo odmítáte. - -Pokud přijmete žádost uBOL o další oprávnění na aktuálním webu, bude moci lépe filtrovat obsah aktuálního webu. - -Výchozí filtrovací režim můžete nastavit na stránce nastavení uBOL. Pokud jako výchozí zvolíte režim optimální nebo kompletní, budete muset uBOL udělit oprávnění ke čtení a úpravě dat na všech webových stránkách. - -Mějte na paměti, že toto je stále nedokončená práce s těmito konečnými cíli: - -- Žádná rozsáhlá oprávnění hostitele v době instalace -- rozšířená oprávnění uděluje explicitně uživatel na jednotlivých stránkách. - -- Zcela deklarativní pro spolehlivost a efektivitu CPU/paměti. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.cv.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.cv.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.cv.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.cv.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.cy.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.cy.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.cy.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.cy.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) yw blocwr cynnwys MV3 sy'n gweithredu heb ganiatâd safonol. +uBO Lite (uBOL) is an MV3-based content blocker. Mae'r set reolau ddiofyn yn cyfateb i set hidlo diofyn uBlock Origin: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.da.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.da.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.da.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.da.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) er en *tilladelsesløs* MV3-baseret indholdsblocker. +uBO Lite (uBOL) er en MV3-baseret indholdsblocker. Standardregelsættet svarer til uBlock Origins standardfiltersæt: @@ -10,21 +10,3 @@ Flere regelsæt kan aktiveres ved at gå til indstillingssiden -- klik på ikonet _Tandhjul_ i pop op-panelet. uBOL er fuldstændig deklarativ, hvilket betyder, at ingen permanent uBOL-proces behøves for at filtreringen kan finde sted, og CSS/JS-injektionsbaseret indholdsfiltrering udføres pålideligt af browseren selv i stedet for af udvidelsen. Dette betyder, at uBOL ikke selv forbruger CPU-/hukommelsesressourcer under indholdsblokeringen -- uBOLs tjenestearbejdsproces er _kun_ nødvendig under interaktion med pop op-panelet eller indstillingssiderne. - -uBOL kræver ikke en omfattende "læse og ændre data" tilladelse under installationen, derfor dens begrænsede egenskaber fra start af sammenlignet med uBlock Origin eller andre indholdsblockere, som kræver omfattende "læse/ændre data" tilladelser under installationen. - -uBOL giver dog mulighed for *eksplicit* at tildele udvidede tilladelser på bestemte websteder efter eget valg, så den bedre kan filtrere på disse websteder vha. kosmetisk filtrering og scriptlet-injektioner. - -For at tildele udvidede tilladelser på et givent websted, åbn pop op-panelet og vælg en højere filtreringstilstand, såsom Optimal eller Komplet. - -Browseren advarer derefter om virkningerne af de ekstra tildelte tilladelser, som udvidelsen anmoder om på det aktuelle websted, og man vil skulle fortælle browseren, hvorvidt anmodningen accepteres eller afslås. - -Accepteres uBOLs anmodning om ekstra tilladelser på det aktuelle websted, vil den bedre kunne filtrere indhold på webstedet. - -Standardfiltreringstilstanden kan angives via uBOLs indstillingsside. Hvis tilstanden Optimal eller Komplet vælges som standardtilstand, skal uBOL tildeles tilladelse til at læse og ændre data på alle websteder. - -Husk dog, at dette stadig er et igangværende arbejde med disse slutmål: - -- Ingen omfattende værtstilladelser under installationen -- udvidede tilladelser tildeles eksplicit af brugeren på webstedsbasis. - -- Fuldstændig deklarativ for pålidelighed og CPU-/hukommelseseffektivitet. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.de.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.de.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.de.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.de.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) ist ein Inhaltsblocker, der *ohne Berechtigungen* auskommt und auf MV3 basiert. +uBO Lite (uBOL) ist ein MV3-basierter Inhaltsblocker. Die Standardregeln entsprechen den Standardfiltern von uBlock Origin: @@ -10,21 +10,3 @@ Sie können weitere Regeln aktivieren, indem Sie die Einstellungen aufrufen — klicken Sie dazu im Pop-up-Fenster auf das Symbol mit den _Zahnrädern_. uBOL ist vollständig deklarativ, d. h. es ist kein dauerhafter uBOL-Prozess für das Filtern erforderlich, und die auf CSS/JS-Injektion basierende Inhaltsfilterung wird zuverlässig vom Browser selbst und nicht von der Erweiterung durchgeführt. Das bedeutet, dass uBOL selbst keine CPU-/Speicherressourcen verbraucht, während der Inhalt blockiert wird — der uBOL-Service-Worker-Prozess wird _nur_ benötigt, wenn Sie mit dem Pop-up-Fenster oder den Optionen interagieren. - -uBOL erfordert bei der Installation keine weitreichende Berechtigung zum Lesen und Ändern von Daten, daher sind die Möglichkeiten im Vergleich zu uBlock Origin oder anderen Inhaltsblockern, die bei der Installation weitreichende Berechtigungen zum Lesen und Ändern von Daten erfordern, von vornherein begrenzt. - -Allerdings können Sie mit uBOL *explizit* erweiterte Berechtigungen für bestimmte Websites Ihrer Wahl erteilen, sodass diese Websites durch kosmetisches Filtern und Scriptlet-Injektionen besser gefiltert werden können. - -Um erweiterte Berechtigungen für eine bestimmte Website zu erteilen, öffnen Sie das Pop-up-Fenster und wählen Sie einen stärkeren Filtermodus wie »Optimal« oder »Vollständig«. - -Der Browser warnt Sie anschließend über die Auswirkungen der zusätzlichen Berechtigungen, die von der Erweiterung für die aktuelle Website angefordert werden, und Sie können entscheiden, ob Sie zustimmen oder ablehnen. - -Wenn Sie die Anfrage von uBOL nach zusätzlichen Berechtigungen für die aktuelle Website zustimmen, kann uBOL die Inhalte für die aktuelle Website besser filtern. - -Sie können den Standardfiltermodus in den Optionen von uBOL festlegen. Wenn Sie den Modus »Optimal« oder »Vollständig« als Standardmodus wählen, müssen Sie uBOL die Berechtigung erteilen, Daten auf allen Websites lesen und ändern zu dürfen. - -Denken Sie daran, dass sich dieses Projekt noch in Entwicklung befindet und folgende Ziele verfolgt: - -- Keine weitreichenden Host-Berechtigungen bei der Installation — erweiterte Berechtigungen werden explizit von Ihnen für jede einzelne Website erteilt. - -- Vollständig deklarativ für Zuverlässigkeit und CPU-/Speichereffizienz. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.el.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.el.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.el.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.el.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -Το uBO Lite (uBOL) είναι πρόσθετο φραγής περιεχομένου που *δεν απαιτεί δικαιώματα* και βασίζεται στο MV3. +Το uBO Lite (uBOL) είναι εργαλείο φραγής περιεχομένου, που βασίζεται στο MV3. Το προεπιλεγμένο σύνολο κανόνων αντιστοιχεί στο προεπιλεγμένο σύνολο φίλτρων του uBlock Origin: @@ -10,21 +10,3 @@ Μπορείτε να προσθέσετε περισσότερα σύνολα κανόνων από τη σελίδα επιλογών -- κάντε κλικ στο εικονίδιο _γρανάζι_ στον αναδυόμενο πίνακα. Το uBOL είναι εξ'ολοκλήρου δηλωτικό, πράγμα που σημαίνει ότι δεν υπάρχει ανάγκη για μόνιμη διαδικασία uBOL για να πραγματοποιηθεί το φιλτράρισμα, και το φιλτράρισμα περιεχομένου που βασίζεται σε έγχυση CSS/JS εκτελείται αξιόπιστα από το ίδιο το πρόγραμμα περιήγησης και όχι από την επέκταση. Αυτό σημαίνει ότι το ίδιο το uBOL δεν καταναλώνει πόρους CPU/μνήμης ενώ ο αποκλεισμός περιεχομένου είναι σε εξέλιξη -- η διαδικασία του service worker του uBOL απαιτείται _μόνο_ όταν αλληλεπιδράτε με τον αναδυόμενο πίνακα ή τις σελίδες επιλογών. - -Το uBOL δεν απαιτεί ευρεία άδεια "ανάγνωσης και τροποποίησης δεδομένων" κατά τον χρόνο εγκατάστασης, επομένως έχει εξαρχής περιορισμένες δυνατότητές σε σύγκριση με το uBlock Origin ή άλλα προγράμματα αποκλεισμού περιεχομένου που απαιτούν ευρείες άδειες "ανάγνωσης/τροποποίησης δεδομένων" κατά την εγκατάσταση. - -Ωστόσο, το uBOL σάς επιτρέπει *ρητά* να εκχωρείτε εκτεταμένες άδειες σε συγκεκριμένους ιστότοπους της επιλογής σας, ώστε να μπορεί να φιλτράρει καλύτερα σε αυτούς τους ιστότοπους χρησιμοποιώντας κοσμητικό φιλτράρισμα και έγχυση scriptlet. - -Για να εκχωρήσετε εκτεταμένα δικαιώματα σε έναν δεδομένο ιστότοπο, ανοίξτε το αναδυόμενο πλαίσιο και επιλέξτε μια υψηλότερη λειτουργία φιλτραρίσματος, όπως Βέλτιστη ή Ολοκληρωμένη. - -Στη συνέχεια, το πρόγραμμα περιήγησης θα σας προειδοποιήσει για τα αποτελέσματα της χορήγησης των πρόσθετων δικαιωμάτων που ζητούνται από την επέκταση στον τρέχοντα ιστότοπο και θα πρέπει να ενημερώσετε το πρόγραμμα περιήγησης εάν αποδέχεστε ή απορρίπτετε το αίτημα. - -Εάν αποδεχτείτε το αίτημα του uBOL για πρόσθετα δικαιώματα στον τρέχοντα ιστότοπο, θα μπορεί να φιλτράρει καλύτερα το περιεχόμενο για τον τρέχοντα ιστότοπο. - -Μπορείτε να ορίσετε την προεπιλεγμένη λειτουργία φιλτραρίσματος από τη σελίδα επιλογών του uBOL. Εάν επιλέξετε τη λειτουργία Βέλτιστη ή Ολοκληρωμένη ως προεπιλεγμένη, θα πρέπει να εκχωρήσετε στην uBOL την άδεια ανάγνωσης και τροποποίησης δεδομένων σε όλους τους ιστότοπους. - -Λάβετε υπόψη ότι αυτό είναι ακόμη ένα έργο σε εξέλιξη, με αυτούς τους τελικούς στόχους: - -- Να μην υπάρχουν ευρείες άδειες hosts κατά την εγκατάσταση -- οι εκτεταμένες άδειες παραχωρούνται ρητά από τον χρήστη σε βάση ανά τοποθεσία. - -- Εντελώς δηλωτικό για αξιοπιστία και απόδοση CPU/μνήμης. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.en_GB.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.en_GB.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.en_GB.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.en_GB.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.eo.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.eo.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.eo.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.eo.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.es.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.es.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.es.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.es.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) es un bloqueador de contenido con *menos permisos* basado en MV3. +uBO Lite (uBOL) es un bloqueador de contenido basado en MV3. Por defecto ya trae configuradas las siguientes listas de filtros: @@ -10,21 +10,3 @@ Puedes habilitar más conjuntos de reglas visitando la página de opciones, haz clic en el icono de _engranaje_ del panel emergente. uBOL es completamente declarativo, lo que significa que no hay necesidad de un proceso uBOL permanente para que se produzca el filtrado, y el filtrado de contenido basado en la inyección de CSS/JS se realiza de forma confiable por el propio navegador en lugar de la extensión. Esto significa que uBOL en sí mismo no consume recursos de CPU/memoria mientras el bloqueo de contenido está en curso, el proceso service worker de uBOL se requiere _solo_ cuando se interactúa con el panel emergente o las páginas de opciones. - -uBOL no requiere amplios permisos para "leer y modificar datos" en el momento de la instalación, de ahí sus capacidades limitadas en comparación con uBlock Origin u otros bloqueadores de contenido que requieren amplios permisos para "leer y modificar datos" en el momento de la instalación. - -Sin embargo, uBOL te permite otorgar *explícitamente* permisos extendidos en sitios específicos de tu elección para que pueda filtrar mejor en esos sitios usando filtrado cosmético e inyecciones de scriptlet. - -Para otorgar permisos extendidos en un sitio determinado, abre el panel emergente y elige un modo de filtrado superior, como óptimo o completo. - -Después el navegador te advertirá sobre los efectos de otorgar los permisos adicionales solicitados por la extensión en el sitio actual, y deberás indicar al navegador si aceptas o rechazas la solicitud. - -Si aceptas la solicitud de uBOL para permisos adicionales en el sitio actual, será capaz de filtrar mejor el contenido para el sitio actual. - -Puedes establecer el modo de filtrado predeterminado desde la página de opciones de uBOL. Si eliges como predeterminado el modo óptimo o completo, tendrás que otorgar a uBOL el permiso para leer y modificar datos en todos los sitios web. - -Téngase en cuenta que esto todavía es un trabajo en progreso, con estos objetivos finales: - -- Sin amplios permisos de host en el momento de la instalación, los permisos ampliados son otorgados explícitamente por el usuario en cada sitio. - -- Completamente declarativo para confiabilidad y eficiencia de la CPU/memoria. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.et.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.et.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.et.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.et.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) on MV3-l põhinev *lubadeta* sisutõkestaja. +uBO Lite (uBOL) on MV3-l põhinev sisutõkestaja. Tavaline reeglitekogum vastab uBlock Origini tavalisele filtritekogumile: @@ -10,21 +10,3 @@ Rohkem reegleid valikutest ehk toksake _Cogs_ ikooni hüpikpaneelis. uBOL on läbinisti deklaratiivne ehk filtreerimiseks pole vaja kogu aeg töötavat uBOLi protsessi ja CSS/JS süstipõhist sisu filtreerib tegelikult brauser, mitte laiendus. Teisisõnu, uBOL ei kasuta sisu tõkestamisel protsessori/mälu ressursse. uBOLi teenuse toimimise protsessi on vaja _vaid_ juhul, kui kasutate hüpikpaneeli või valikute lehekülgi. - -uBOL ei nõua paigaldamise ajal teadatuntud andmete lugemise ja muutmise luba, seega võrreldes seda nõudva laiendusega uBlock Origin või muu sisutõkestiga on uBOL-i piiratus üks selle funktsioonidest. - -Kuid uBOL võimaldab *selgesõnaliselt* anda täpsemaid lubasid teie valitud veebilehtedele, et neid saaks paremini filtreerida ilufiltrite ja skriptisüstidega. - -Veebilehele täpsustatud lubade andmiseks ava hüpikpaneel ja vali põhjalikum filtreerimisrežiim, näiteks Optimaalne või Põhjalik. - -Seejärel hoiatab veebilehitseja praeguse veebilehe laienduse taotletud täiendavate õiguste andmise tagajärgede eest ja peate veebilehitsejale ütlema, kas nõustute taotlusega või keeldute sellest. - -Kui nõustute uBOLi taotlusega täiendavate õiguste saamiseks praegusel veebilehel, saab see praeguse veebilehe sisu paremini filtreerida. - -Fltreerimise tavarežiimi saate määrata uBOLi valikute lehelt. Kui määrate optimaalse või põhjaliku režiimi tavaliseks, peate andma uBOLile loa kõikide veebilehtede andmete lugemiseks ja muutmiseks. - -Pidage meeles, et see on veel arendamisel, mille lõppeesmärgid on järgmised: - -- Paigaldamise ajal laialdased hostiõigused puuduvad – kasutaja annab laiendatud load selgesõnaliselt ja veebilehe põhiselt. - -- Täiesti deklaratiivne töökindluse ja protsessori/mälu tõhususe osas. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.eu.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.eu.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.eu.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.eu.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) irakargarri blokeatzailea de, baimen gutxiekin eta MV3ean basatua +uBO Lite (uBOL) is an MV3-based content blocker. Lehenespenez, iragazki-zerrenda hauek ditu konfiguratuta: @@ -10,21 +10,3 @@ Ruleta gehiago aktibatu ahal duzu aukerak orria --klikatu _Cogs_ ikonoa panelearen lehioan uBOL guztiz deklaratiboa da, hau da, ez dago uBOL prozesu iraunkor baten beharrik iragazketa gertatzeko, eta CSS/JS injekzioan oinarritutako edukien iragazketa nabigatzaileak berak egiten du fidagarritasunez, luzapenaren arabera beharrean. Horrek esan nahi du uBOLek berak ez duela CPU/memoria baliabiderik kontsumitzen edukien blokeoa martxan dagoen bitartean... uBOLren zerbitzuko langileen prozesua _only_ behar da popup panelarekin edo aukera orriekin elkarreragiten denean. - -uBOLek ez du "irakurtzeko eta aldatzeko datuak" baimen zabalik behar instalazio-unean, horregatik bere gaitasun mugatuak uBlock Origin-ekin alderatuta edo beste eduki-blokeatzaile batzuekin alderatuta, "irakurtzeko eta aldatzeko datuak" baimen zabalak behar dituzten instalazio garaian. - -Hala ere, uBOLek aukera ematen dizu *esplizituki* baimen hedatuak zure aukeratutako gune espezifikoetan, gune horietan hobeto iragazteko iragazte kosmetikoak eta scriptlet injekzioak erabiliz. - -Leku jakin batean baimenak emateko, ireki panel emergentea eta aukeratu goiko iragazteko modu bat, optimo edo oso gisa. - -Nabigatzaileak orduan jakinaraziko dizu zer ondorio dituen luzapenak eskatutako baimen gehigarriak emateak egungo gunean, eta nabigatzaileari esan beharko diozu eskaera onartzen duzun edo uko egiten diozun. - -Baimen gehigarrien eskaera onartzen baduzu, oraingo gunean edukiak hobeto iragazi ahal izango ditu. - -Iragazki modu lehenetsia uBOL-en aukeren orrialdetik ezar dezakezu. Modu hoberena edo osoa aukeratzen baduzu lehenetsitako moduan, uBOL-i webgune guztietako datuak irakurtzeko eta aldatzeko baimena eman beharko diozu. - -Gogoan izan oraindik lan bat dela, azken helburu hauekin: - -- Instalatzeko garaian, ez dago baimen zabalik. Erabiltzaileak esplizituki ematen ditu baimen zabalduak. - -- Erabat deklaratiboa fidagarritasunagatik eta CPU/memoriaren eraginkortasunagatik. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.fa.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.fa.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.fa.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.fa.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. مجموعه قوانین پیش فرض آن مطابق با مجموعه قوانین پیش فرض uBlock Origin است: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.fi.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.fi.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.fi.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.fi.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) on *käyttöoikeudeton* MV3-pohjainen sisällönestotyökalu. +uBO Lite (uBOL) on MV3-pohjainen sisällönestotyökalu. Oletusarvoiset sääntömääritykset vastaavat uBlock Origin -laajennuksen oletuksia: @@ -10,21 +10,3 @@ Voit aktivoida lisää sääntömäärityksiä laajennuksen asetuksista – paina ponnahduspaneelin _Ratas_-kuvaketta. uBOL on täysin deklaratiivinen, eli suodatus ei edellytä pysyvää uBOL-prosessia ja CSS-/JS-koodin manipulointiin perustuva sisällönsuodatuksen suorittaa laajennusprosessin sijaan luotettavasti selainsovellus. Tämän ansiosta itse uBOL ei kuormita prosessoria tai keskusmuistia sisällöneston tapahtuessa -- uBOL:n työprosessia tarvitaan _ainoastaan_ ponnahduspaneelia ja asetussivuja käytettäessä. - -uBOL ei edellytä laajan tietojen luku- ja muokkausoikeuden myöntämistä asennuksen yhteydessä, jonka vuoksi sen oletusarvoiset valmiudet ovat uBlock Originia ja muita vastaavia sisällönestotyökaluja rajallisemmat. - -On kuitenkin mahdollista myöntää *yksinomaisesti* uBOL:lle laajennetut käyttöoikeudet sivustokohtaisesti niiden suodatuksen tehostamiseksi kosmeettisella suodatuksella ja scriplet-injektoinnilla. - -Laajemmat oikeudet myönnetään avoimelle sivustolle avaamalla ponnahduspaneeli ja valitsemalla korkeampi suodatustaso, kuten "Optimaalinen" tai "Täysi". - -Tällöin selain varoittaa laajennuksen avoimelle sivustolle pyytämien käyttöoikeuksien seurauksista ja pyytää hyväksymään tai hylkäämään pyynnön. - -Jos uBOL:n käyttöoikeuspyyntö avoimelle sivustolle hyväksytään, se pystyy suodattamaan sivuston sisältöä tehokkaammin. - -Voit asettaa oletusarvoisen suodatustilan uBOL:n asetussivulta. Jos valitset oletustilaksi Optimaalinen tai Täysi, on uBOL:lle myönnettävä oikeus lukea ja muokata tietojasi kaikilla verkkosivustoilla. - -Huomioithan, että laajennuksen kehitys vielä kesken, seuraavilla tavoitteilla: - -- Laajoja käyttöoikeuksia ei tarvita asennusvaiheesssa, vaan laajennetut oikeudet myönnetään aina sivustokohtaisesti käyttäjän toimesta. - -- Täysin deklaratiivinen luotettavuutta ja prosessorin/muistin kuormituksen keventämiseksi. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.fil.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.fil.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.fil.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.fil.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -Ang uBO Lite (uBOL) ay isang eksperimental at *permission-less* na tagaharang ng content na nakabase sa MV3. +Isang content blocker na nakabase sa MV3 ang uBO Lite (uBOL). Tulad ng uBlock Origin, ito rin ang mga default na listahan ng mga filter: @@ -7,24 +7,6 @@ - EasyPrivacy - Listahan ni Peter Lowe sa mga ad at tracking server (Peter Lowe’s Ad and tracking server list) -You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. +Maaring magpagana ng mas maraming ruleset sa page ng options -- pindutin ang _Cogs_ sa popup na panel. Deklaratibo lamang ang uBOL, kaya hindi nito kailangan ng permanenteng proseso upang mag-filter, at mainam na ginagawa ng browser mismo imbes na ekstensyon ang pagfi-filter sa content na nakabase sa CSS o JS. Ibig-sabihin, hindi kumokonsyumo ng CPU o memorya ang uBOL habang nanghaharang -- ang proseso ng trabahante ng serbisyo ay kailangan _lang_ kung nasa popup panel o pahina ng opsyon ka. - -Hindi kailangan ng uBOL ang malawakang pahintulot para "basahin at baguhin ang data" pagka-install, kaya kung bago pa lang itong install ay limitado ang kakayahan nito kumpara sa uBlock Origin o iba pang mga pangharang ng content na nangangailangan ng malawakang pahintulot para "basahin at baguhin ang data" pagka-install. - -Ngunit, pwede mong *pasadyang* pahintulutan ang uBOL na magkaroon ng pinalawak na pahintulot sa mga website na pipiliin mo para mas mapabuti ang pagfi-filter sa mga site na iyon gamit ang kosmetikong pagfi-filter at injeksyon ng scriptlet. - -Upang bigyan ito ng pinalawak na pahintulot sa isang site, buksan ang popup panel at pumili ng isang mode sa pagfi-filter tulad ng Pinainam o Kumpleto. - -Babalaan ka ng browser tungkol sa mga epekto ng pagbibigay ng karagdagang pahintulot na hinihiling ng ekstensyon sa kasalukuyang site, at kailangan mong tumugon kung pinapahintulutan mo ba ito o hindi. - -Kung tatanggapin mo ang hiling ng uBOL para sa karagdagang mga pahintulot sa kasalukuyang site, mas magiging mainam ang pagfi-filter nito sa content para sa kasalukuyang site. - -Maitatakda mo ang default na mode sa pagfi-filter sa pahina ng mga opsyon ng uBOL. Kailangan mong pahintulutan ang uBOL na basahin o baguhin ang datos sa lahat ng mga website kung pipiliin mo ang Pinainam o Kumpleto bilang default na mode sa pagfi-filter. - -Tandaang kasalukuyan pang binubuo ang ekstensyong ito, at nilalayon nitong: - -- Walang kakailanganing malawakang pahintulot pagka-install -- ibibigay lang ng user ang karagdagang pahintulot sa mga piling site. - -- Deklaratibo lamang upang maging mapagkakatiwalaan at matipid sa CPU at memorya. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.fr.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.fr.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.fr.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.fr.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) est un bloqueur de contenu *sans permission* basé sur le manifeste MV3. +uBO Lite (uBOL) est un bloqueur de contenu basé sur le manifeste MV3. Les règles par défaut correspondent au filtrage par défaut d'uBlock Origin : @@ -10,21 +10,3 @@ Vous pouvez ajouter plus de règles en consultant la page des paramètres -- Cliquez sur l'icône de l'_Engrenage_ dans le panneau pop-up. uBOL est entièrement déclarative, c'est-à-dire qu'il n'y a pas besoin d'un processus uBOL permanent pour filtrer, et le filtrage basé sur l'injection CSS/JavaScript se fait en toute fiabilité par le navigateur lui-même. Cela veut dire qu'en soi, uBOL ne consomme pas de ressources processeur/mémoire pendant le blocage de contenu -- l'agent de service d'uBOL n'est sollicité _que_ quand vous interagissez avec le panneau pop-up ou la page des paramètres. - -Contrairement à uBlock Origin ou d'autres extensions de blocage, uBOL ne nécessite pas de larges permissions de "lecture/modification des données" au moment de l'installation, ce qui explique ses capacités au départ limitées. - -Cependant, uBOL vous permet *explicitement* d'accorder des permissions étendues sur les sites Web de votre choix, pour qu'elle puisse mieux les filtrer en utilisant le filtrage esthétique et des injections de scriptlet. - -Pour accorder des permissions étendues sur un site Web donné, ouvrez le panneau pop-up et choisissez un mode de filtrage plus élevé comme le mode Optimal ou le mode Complet. - -Le navigateur vous préviendra alors des effets de l'accord de permissions additionnelles requises par l'extension sur le site Web en cours de consultation et vous devrez indiquer votre choix au navigateur (Accepter/Refuser). - -Si vous acceptez la requête d'uBOL pour des permissions additionnelles sur le site Web en cours de consultation, le filtrage de son contenu sera renforcé. - -Vous pouvez définir le mode de filtrage par défaut depuis la page des paramètres d'uBOL. Si vous choisissez le mode Optimal ou Complet en tant que mode par défaut, vous devrez accorder à uBOL l'autorisation de lire et de modifier des données sur tous les sites Web. - -Gardez à l'esprit que c'est en cours de développement, avec comme objectifs : - -- De ne pas accorder de permissions globales au moment de l'installation -- les permissions étendues s'accordent explicitement par l'utilisateur site par site. - -- De travailler de manière entièrement déclarative pour la fiabilité et l'efficacité processeur/mémoire. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.fy.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.fy.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.fy.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.fy.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is in *tastimmingsleaze* MV3-basearre ynhâldsblokkearder. +uBO Lite (uBOL) is in MV3-basearre ynhâldsblokkearder. De standert regelset komt oerien mei de standert filterset fan uBlock Origin: @@ -10,21 +10,3 @@ Jo kinne mear regelsets ynskeakelje troch de opsjesside te besykjen – klik op it _tântsjilpiktogram_ yn it pop-uppaniel. uBOL is folslein deklaratyf, wat betsjut dat in permanint uBOL-proses foar de filtering net nedich is, en ynhâldsfiltering op basis fan CSS/JS-ynjeksje op in betroubere manier troch de browser sels útfierd wurdt yn stee fan de útwreiding. Dit betsjut dat uBOL sels gjin CPU-/ûnthâldboarnen brûkt wylst ynhâldsblokkearring aktyf is – it serviceworker-proses fan uBOL is _allinnich_ fereaske as jo mei it pop-uppaniel of de opsjessiden wurkje. - -uBOL fereasket gjin brede tastimming foar it ‘lêzen en oanpassen fan gegevens’ wylst ynstallaasje, fan dêr de beheinde ynboude mooglikheden dêrfan yn fergeliking mei uBlock Origin of oare ynhâldsblokkearders dy’t brede tastimmingen foar it ‘lêzen en oanpassen fan gegevens’ fereaskje wylst de ynstallaasje. - -Jo kinne yn uBOL echter *eksplisyt* wiidweidige tastimmingen ferliene op bepaalde websites fan jo kar, sadat it op dy websites better filterje kin fia kosmetyske filtering en scriptlet-ynjeksjes. - -Om wiidweidige tastimmingen op in bepaalde website te ferlienen, iepenje jo it pop-uppaniel en kieze jo in hegere filtermodus, lykas Optimaal of Folslein. - -De browser warskôget jo dan oer de gefolgen fan it ferlienen fan de troch de útwreiding oanfrege oanfoljende tastimmingen op de aktuele website, en jo moatte de browser witte litte oft jo de oanfraach akseptearje of wegerje. - -As jo de oanfraach fan uBOL foar oanfoljende tastimmingen op de aktuele website akseptearje, sil it ynhâld foar de aktuele website better filterje kinne. - -Jo kinne de standert filtermodus ynstelle fan de opsjesside fan uBOL ôf. As jo de modus Optimaal of Folslein as de standertmodus kieze, moatte jo uBOL de tastimming foar it lêzen en oanpassen fan gegevens op alle websites te ferlienen. - -Unthâld dat dit noch wurk yn útfiering is, mei dizze eindoelen: - -- Gjin brede host-tastimmingen wylst ynstallaasje – wiidweidige tastimmingen wurde eksplisyt en per website ferliend troch de brûker. - -- Folslein deklaratyf omwille fan betrouberheid en CPU-/ûnthâldeffisjinsje. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.gl.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.gl.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.gl.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.gl.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) é un bloqueador de contido baseado en MV3 *sen permisos. +uBO Lite (uBOL) é un bloqueador de contido baseado en MV3. O conxunto de regras predeterminado corresponde ao conxunto de filtros predeterminado de uBlock Origin: @@ -10,21 +10,3 @@ Podes activar máis grupos de regras indo á páxina de opcións -- preme na roda dentada no panel emerxente. uBOL é totalmente declarativo, o que significa que non é necesario un proceso permanente de uBOL para que se produza o filtrado e o filtrado de contido baseado en inxección de CSS/JS realízao de forma fiable o propio navegador en lugar da extensión. Isto significa que o propio uBOL non consume recursos de CPU/memoria mentres o bloqueo de contido está en curso -- o proceso do traballador do servizo de uBOL é necesario _só_ cando interactúas co panel emerxente ou coas páxinas de opcións. - -uBOL non require amplos permisos de "ler e modificar datos" no momento da instalación, de aí as súas capacidades limitadas fóra da caixa en comparación con uBlock Origin ou outros bloqueadores de contido que requiren amplos permisos de "ler e modificar datos" no momento da instalación. - -Non obstante, uBOL permítelle *de forma explícita* conceder permisos estendidos en sitios específicos da súa elección para que poida filtrar mellor neses sitios mediante filtrado cosmético e inxeccións de scriptlet. - -Para conceder permisos estendidos nun sitio determinado, abra o panel emerxente e escolle un modo de filtrado superior, como Óptimo ou Completa. - -A continuación, o navegador avisará sobre os efectos da concesión dos permisos adicionais solicitados pola extensión no sitio actual, e terá que indicarlle ao navegador se acepta ou rexeita a solicitude. - -Se aceptas a solicitude de uBOL de permisos adicionais no sitio actual, poderá filtrar mellor o contido do sitio actual. - -Podes establecer o modo de filtrado predeterminado desde a páxina de opcións de uBOL. Se escolle o modo Óptimo ou Completo como o predeterminado, terá que conceder a uBOL o permiso para ler e modificar datos en todos os sitios web. - -Teña en conta que este aínda é un traballo en curso, cos seguintes obxectivos finais: - -- Non hai permisos de host amplos no momento da instalación. Os permisos estendidos son concedidos explícitamente polo usuario por cada sitio. - -- Totalmente declarativo para a fiabilidade e a eficiencia da CPU/memoria. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.gu.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.gu.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.gu.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.gu.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.he.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.he.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.he.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.he.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) הוא חוסם תוכן *ללא הרשאות* מבוסס MV3. +uBO Lite (uBOL) הוא חוסם תוכן מבוסס MV3. ערכת הכללים ברירת מחדל שמתכתבת עם ערכת המסננים של uBlock Origin: @@ -10,21 +10,3 @@ ניתן לאפשר קבוצות חוקים נוספות בדף האפשרויות - עם לחיצה על סמליל _גלגלי השיניים_ בחלונית הקופצת. uBOL הוא הכרזתי לחלוטין, כלומר אין צורך בתהליך uBOL קבוע כדי שהסינון יתרחש, וסינון תוכן מבוסס הזרקת CSS/JS מבוצע באופן אמין על ידי הדפדפן עצמו ולא על ידי ההרחבה. המשמעות היא ש־uBOL עצמו לא צורכך משאבי מעבד/זיכרון בזמן שחסימת התוכן מתרחשת – תהליך ה־service worker של uBOL נדרש _אך ורק_ בזמן הידוד עם החלון הקופץ או עם עמוד האפשרויות. - -uBOL לא דורש הרשאת "קריאה ושינוי נתונים" נרחבות במהלך ההתקנה, לכן היכולות המוגבלות שלה הישר מהקופסה בהשוואה ל־uBlock Origin או חוסמי תוכן אחרים הדורשים הרשאות "קריאה ושינוי נתונים" נרחבות כבר בזמן ההתקנה. - -עם זאת, uBOL מאפשר להעניק *באופן מפורש* הרשאות נרחבות לאתרים מסויימים על פי בחירה, למיטוב הסינון באתרים אלה, באמצעות סינון קוסמטי והזרקות סקריפלטים. - -כדי להעניק הרשאות נרחבות באתר נתון, נא לפתוח את הלוח הקופץ ולבחור באופן סינון גבוה יותר כגון מיטבי או מלא. - -לאחר מכן, תוצג אזהרת דפדפן על השפעות מתן הרשאות נוספות אותן מבקשת ההרחה באתר הנוכחי, הדפדפן ימתין לקבלת תשובה האם לקבל או לדוחות את בקשת ההרשאה. - -אם תקבל את הבקשה של uBOL להרשאות נוספות באתר הנוכחי, הוא יוכל לסנן טוב יותר תוכן עבור האתר הנוכחי. - -ניתן להגדיר את מצב הסינון המוגדר כברירת מחדל מדף האפשרויות של uBOL. אם הבחירה היתה באופןסינון מיטבי או מלא כברירת המחדל, יידרש להעניק ל־uBOL הרשאת קריאה שנוי נתונים בכל אתרי הרשת. - -יש לזכור שזו עדיין 'עבודה בתהליך', עם המטרות הבאות: - -- אין הרשאות מארח רחבות בזמן ההתקנה -- הרשאות מורחבות מוענקות במפורש על ידי המשתמש על בסיס לכל אתר. - -הכרזתי לחלוטין, אמין ויעיל בצריכת משאבי מעבד/זיכרון. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.hi.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.hi.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.hi.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.hi.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) एक *अनुमति-रहित* MV3-आधारित कन्टेन्ट ब्लॉकर है। +uBO Lite (uBOL) is an MV3-based content blocker. डिफ़ॉल्ट रूलसेट uBlock Origin के डिफ़ॉल्ट फ़िल्टर सेट के अनुरूप होता है: @@ -10,21 +10,3 @@ आप विकल्प पृष्ठ पर जाकर और अधिक नियम-सेट सक्षम कर सकते हैं -- पॉपअप पैनल में _Cogs_ आइकन पर क्लिक करें। uBOL पूरी तरह से वर्णनात्मक है, जिसका यह अर्थ है कि फ़िल्टरिंग के लिए एक स्थायी uBOL प्रक्रिया की कोई आवश्यकता नहीं है, और CSS/JS इंजेक्शन-आधारित कन्टेन्ट फ़िल्टरिंग एक्सटेंशन के बजाय ब्राउज़र द्वारा विश्वसनीय रूप से की जाती है। इसका यह अर्थ है कि कन्टेन्ट ब्लॉक करते समय uBOL द्वारा सीपीयू/मेमोरी संसाधनों का उपभोग स्वयं नहीं किया जाता है -- uBOL की सर्विस प्रोसेस की आवश्यकता _केवल_ तब होती है जब आप पॉपअप पैनल या विकल्प पृष्ठों पर कोई अंत:क्रिया करते हैं। - -uBOL को इन्सटॉल करते समय "डेटा को पढ़ने और संशोधित करने" की व्यापक अनुमति की आवश्यकता नहीं होती है, अतः इसकी सीमित क्षमताओं तत्काल उपयोगिता की तुलना में uBlock Origin या अन्य कन्टेन्ट ब्लॉकर को इन्सटॉलेशन के समय "डेटा को पढ़ने और संशोधित करने" की व्यापक अनुमतियों की आवश्यकता होती है। - -हालांकि, uBOL आपको अपनी मनपसंद विशिष्ट साइटों पर विस्तारित अनुमतियां देना *स्पष्ट रूप से* अनुमत करता है ताकि यह कॉस्मेटिक फ़िल्टरिंग और स्क्रिप्टलेट इंजेक्शन का उपयोग करके उन साइटों पर अच्छी तरह से फ़िल्टर कर सके। - -किसी एक साइट पर विस्तारित अनुमतियां देने के लिए, पॉपअप पैनल खोलें और उच्च फ़िल्टरिंग मोड, जैसे कि 'अनुकूलतम' (ऑप्टिमल) या 'पूर्ण' (कंपलीट) चुनें। - -इसके बाद ब्राउज़र द्वारा आपको वर्तमान साइट पर एक्सटेंशन द्वारा अनुरोधित अतिरिक्त अनुमतियों को देने के प्रभावों के बारे में चेतावनी दी जाएगी, और आपको ब्राउज़र को यह बताना होगा कि आप अनुरोध को स्वीकार करते हैं या अस्वीकार करते हैं। - -यदि आप वर्तमान साइट पर अतिरिक्त अनुमतियों के लिए uBOL के अनुरोध को स्वीकार करते हैं, तो यह वर्तमान साइट के लिए कन्टेन्ट अच्छी तरह से फ़िल्टर करने में सक्षम होगा। - -आप uBOL के विकल्प पृष्ठ से डिफ़ॉल्ट फ़िल्टरिंग मोड को सेट कर सकते हैं। यदि आप 'अनुकूलतम' (ऑप्टिमल) या 'पूर्ण' (कंपलीट) मोड को डिफ़ॉल्ट रूप से चुनते हैं, तो आपको uBOL को सभी वेबसाइटों पर डेटा को पढ़ने और संशोधित करने के लिए अनुमत करना होगा। - -ध्यान रखें कि यह कार्य अभी भी प्रगतिधीन है, और इसके न‍िम्नांकित अंतिम लक्ष्यों तय किये गए हैं: - -- इन्सटॉल करते समय कोई व्यापक होस्ट अनुमतियां नहीं -- विस्तारित अनुमतियां उपयोगकर्ता द्वारा हर एक साइट के आधार पर स्पष्ट रूप से दी जाती हैं। - -- विश्वसनीयता और सीपीयू/मेमोरी दक्षता के लिए पूरी तरह वर्णनात्मक। diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.hr.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.hr.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.hr.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.hr.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) je bloker sadržaja *bez dopuštenja* baziran na MV3. +uBO Lite (uBOL) je bloker sadržaja baziran na MV3. Zadana lista pravila odgovara uBlock Origin-ovoj zadanoj listi filtera: @@ -10,21 +10,3 @@ Možete omogućiti više skupova pravila tako što ćete posjetiti stranicu s opcijama -- kliknite ikonu _Cogs_ na skočnoj ploči. uBOL je u potpunosti deklarativan, što znači da nema potrebe za trajnim uBOL procesom za filtriranje, a filtriranje sadržaja temeljeno na ubacivanju CSS/JS pouzdano izvodi sam preglednik, a ne ekstenzija. To znači da sam uBOL ne troši CPU/memorijske resurse dok je blokiranje sadržaja u tijeku -- uBOL-ov servisni radni proces potreban je _samo_ kada komunicirate s skočnom pločom ili stranicama s opcijama. - -uBOL ne zahtijeva široku dozvolu za "čitanje i izmjenu podataka" u vrijeme instalacije, stoga ima zadane ograničene mogućnosti u usporedbi s uBlock Origin ili drugim blokatorima sadržaja koji zahtijevaju veću dozvolu za "čitanje i izmjenu podataka" u vrijeme instalacije. - -Međutim, uBOL vam omogućuje da *eksplicitno* dodijelite proširena dopuštenja na određenim web-stranicama po vašem izboru tako da može bolje filtrirati te web-stranice koristeći kozmetičko filtriranje i injekcijske skripte. - -Da biste dodijelili proširena dopuštenja na određenoj web stranici, otvorite skočnu ploču i odaberite viši način filtriranja kao što je Optimalno ili Potpuno. - -Preglednik će vas tada upozoriti o učincima dodjele dodatnih dopuštenja koje traži ekstenzija na trenutnom mjestu, a vi ćete morati reći pregledniku prihvaćate li ili odbijate zahtjev. - -Ako prihvatite uBOL-ov zahtjev za dodatnim dozvolama na trenutnoj stranici, moći će bolje filtrirati sadržaj na njoj. - -Zadani način filtriranja možete postaviti na stranici s opcijama uBOL-a. Ako kao zadano odaberete Optimalni ili Potpuni način rada, morati ćete dati uBOL-u dopuštenje za čitanje i izmjenu podataka na svim web stranicama. - -Imajte na umu da je ovo još u tijeku, sa sljedećim krajnjim ciljevima: - -- Nema širokih dopuštenja hosta u vrijeme instalacije -- proširena dopuštenja izričito dodjeljuje korisnik za svaku pojedinačnu stranicu. - -- Potpuno deklarativno za pouzdanost i učinkovitost CPU/memorije. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.hu.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.hu.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.hu.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.hu.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -A uBO Lite (uBOL) egy *engedélyt nem igénylő* MV3-alapú tartalomblokkoló. +A uBO Lite (uBOL) egy MV3-alapú tartalomblokkoló. Az alapértelmezett szabálykészlet megfelel a uBlock Origin alapértelmezett szűrőkészletének: @@ -10,21 +10,3 @@ További szabályokat engedélyezhet a beállítások oldalon – kattintson a _Fogaskerekek_ ikonra a felugró panelen. A uBOL teljes mértékben deklaratív, vagyis nincs szükség állandó uBOL folyamatra a szűréshez, és a CSS/JS injektálás-alapú tartalomszűrést maga a böngésző végzi megbízhatóan, nem pedig a kiegészítő. Ez azt jelenti, hogy az uBOL maga nem fogyaszt CPU/memória erőforrásokat, amíg a tartalom blokkolása folyamatban van – az uBOL service worker folyamatára _csak_ akkor van szükség, amikor az felugró panellel vagy a beállítási oldalakkal érintkezik. - -A uBOL nem igényel széles körű „adatok módosítása és olvasása” engedélyt a telepítéskor, ezért korlátozott képességei vannak a uBlock Originhez vagy más tartalomblokkolókhoz képest, amelyek széles körű „adatok olvasása és módosítása” engedélyeket igényelnek a telepítésükkor. - -Az uBOL azonban lehetővé teszi, hogy *kifejezetten* kiterjesztett engedélyeket adjon az Ön által választott bizonyos webhelyeknél, hogy jobban szűrhessen ezeken a webhelyeken kozmetikai szűréssel és parancsfájlbeillesztéssel. - -Ha kiterjesztett engedélyeket szeretne adni egy adott webhelyen, nyissa meg a felugró panelt, és válasszon magasabb szűrési módot, mint az Optimális vagy a Teljes. - -A böngésző ekkor figyelmezteti Önt a bővítmény által kért további engedélyek megadásának hatásaira az aktuális webhelyen, és közölnie kell a böngészővel, hogy elfogadja-e vagy elutasítja a kérést. - -Ha elfogadja az uBOL további engedélyekre vonatkozó kérését az aktuális webhelyen, akkor jobban tudja szűrni az aktuális webhely tartalmát. - -Az alapértelmezett szűrési módot az uBOL beállítási oldalán állíthatja be. Ha az Optimális vagy a Teljes módot választja alapértelmezettként, akkor az uBOL-nak engedélyt kell adnia az adatok olvasására és módosítására az összes webhelyen. - -Ne feledje, hogy ez még egy folyamatban lévő fejlesztés, a következő célokkal: - -- Nincsenek széles körű kiszolgálókra vonatkozó engedélyek a telepítés során – a kiterjesztett engedélyeket a felhasználó kifejezetten webhelyenként adja meg. - -- Teljesen deklaratív a nagyobb megbízhatóság, illetve CPU- és memóriahatékonyság érdekében. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.hy.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.hy.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.hy.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.hy.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL)-ը բովանդակության արգելափակիչ է, որը *չի պահանջում թույլտվություններ*, և հիմնված է MV3-ի վրա։ +uBO Lite (uBOL) is an MV3-based content blocker. Կանոնների լռելյայն փաթեթը համապատասխանում է uBlock Origin-ի լռելյայն զտիչների փաթեթին։ @@ -10,25 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL-ն ամբողջությամբ դեկլարատիվ է, այսինքն՝ զտման համար անընդհատ կատարվող uBOL գործընթացի կարիք չկա, իսկ CSS/JS արմատավորման վրա հիմնված բովանդակության զտումը հուսալիորեն իրականացվում է զննիչի կողմից, այլ ոչ թե ընդլայնման միջոցով։ Սա նշանակում է, որ uBOL հավելումը չի սպառում մշակիչի/հիշողության որևէ ռեսուրս, երբ տեղի է ունենում գովազդի արգելափակումը. uBOL աշխատանքային գործընթացն աշխատում է _միայն_ երբ Դուք փոփոխություններ եք կատարում դուրս լողացող վահանակում կամ ընտրանքների էջում։ - -uBOL-ը տեղադրման ժամանակ «տվյելները լիովին ընթերցելու և փոփոխելու» թույլտվություն չի պահանջում, ուստի այն ունի սահմանափակ հնարավորություններ՝ համեմատած uBlock Origin-ի և բովանդակության այլ արգելափակիչների հետ, որոնք տեղադրման ժամանակ պահանջում են այդպիսի թույլտվություն։ - -Однако uBOL позволяет *намеренно* давать расширенные разрешения для определенных сайтов - по вашему усмотрению, чтобы эффективнее работать, используя косметическую фильтрацию и scriptlet-внедрения. - -Այնուամենայնիվ, uBOL-ը թույլ է տալիս *դիտմամբ* տրամադրել ընդլայնված թույլտվություններ Ձեր ընտրած կայքերի համար, որպեսզի այն կարողանա էլ ավելի լավ զտել այդ կայքերը՝ օգտագործելով կոսմետիկ զտումը և սցենարների արմատավորումները։ - -Для предоставления расширенных разрешений на текущем сайте - откройте всплывающую панель и выберите повышенный режим фильтрации: Оптимальный или Полный. - -Ընթացիկ կայքում ընդլայնված թույլտվություններ տրամադրելու համար բացեք դուրս լողացող վահանակը և ընտրեք ընդլայնված զտման ռեժիմ՝ Գերադասելի կամ Ամբողջական։ - -Այնուհետև զննիչը կզգուշացնի Ձեզ ընթացիկ կայքում ընդլայնման կողմից պահանջվող լրացուցիչ թույլտվությունների տրամադրման հետևանքների մասին, և Դուք պետք է ընտրեք՝ ընդունում եք, թե մերժում եք հայտը։ - -Եթե ​​ընդունեք uBOL-ին լրացուցիչ թույլտվություններ տալու հայտը, ապա այն կկարողանա ավելի արդյունավետ կերպով զտել ընթացիկ կայքի բովանդակությունը։ - -Դուք կարող եք սահմանել զտման լռելյայն ռեժիմը uBOL-ի ընտրանքների էջում։ Եթե ​​որպես լռելյայն ընտրեք «Գերադասելի» կամ «Ամբողջական» ռեժիմը, պետք կլինի uBOL-ին թույլտվություն տրամադրեք կարդալու և փոփոխելու տվյալները բոլոր կայքերում։ - -Հիշեք, որ այս նախագիծը մշակման ակտիվ փուլում է, որ ունի հետևյալ նպատակները. - -- Տեղադրման ընթացքում Սահմանափակ թույլտվություններով աշխատանք տեղադրման ժամանակ. օգտվողը ընդլայնված թույլտվություններ է տալիս իր հայեցողությամբ, յուրաքանչյուր կայքի համար առանձին։ - -- Ամբողջովին դեկլարատիվ է հուսալիության և մշակիչի/հիշողության արտադրողականության համար։ diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.id.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.id.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.id.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.id.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) adalah pemblokir konten berbasis MV3 yang membutuhkan lebih sedikit perizinan. +uBO Lite (uBOL) adalah pemblokir konten berbasis MV3. Kumpulan aturan bawaan sesuai dengan kumpulan penyaringan bawaan uBlock Origin: @@ -7,24 +7,6 @@ - EasyPrivacy - Daftar server iklan dan pelacak Peter Lowe -Anda dapat mengaktifkan lebih banyak kumpulan pengaturan dengan mengunjungi halaman opsi - klik ikon _Cogs_ pada panel popup. +Anda dapat mengaktifkan lebih banyak rangkaian aturan dengan mengunjungi halaman opsi -- klik ikon _Cogs_ di panel popup. -uBOL sepenuhnya deklaratif, yang mana tidak membutuhkan proses permanen uBOL agar penyaringan dapat terjadi, dan penyaringan konten berbasis injeksi CSS/JS dilakukan sepenuhnya oleh peramban itu sendiri ketimbang oleh ekstensi. Ini berarti bahwa uBOL sendiri tidak mengkonsumsi sumber daya CPU/memori selama melakukan pemblokiran konten -- proses pekerja layanan uBOL dibutuhkan _hanya_ ketika Anda berinteraksi dengan panel popup atau opsi halaman. - -uBOL tidak membutuhkan izin "baca dan modifikasi data" pada waktu penginstalan, maka kemampuannya lebih terbatas jika dibandingkan dengan uBlock Origin atau pemblokir konten lain yang memerlukan izin "baca dan modifikasi data" pada waktu penginstalan. - -Namun, uBOL memberi anda opsi untuk *secara eksplisit* memberikan izin tambahan pada situs pilihan Anda, sehingga dapat memfilter situs tersebut dengan lebih baik menggunakan pemfilteran kosmetik dan injeksi scriptlet. - -Untuk memberikan izin tambahan pada situs tertentu, buka panel popup dan pilih mode pemfilteran yang lebih tinggi seperti Optimal atau Complete. - -Perambaan kemudian akan memperingatkan anda tentang efek memberikan izin tambahan yang diminta oleh ekstensi pada situs saat ini, dan Anda harus memberitahu perambaan apakah anda menyetujui atau menolak permintaan. - -Jika Anda menyetujui permintaan uBOL untuk izin tambahan pada situs terkini, uBOL akan dapat menyaring konten dengan lebih baik untuk situs terkini. - -Anda dapat menentukan mode penyaringan bawaan dari halaman pengaturan uBOL Jika Anda memilih mode Optimal atau Complete sebagai mode bawaan, Anda perlu memberikan uBOL izin untuk membaca dan mengubah data pada semua situs web. - -Mohon diingat bahwa ini msaih dalam tahap proses pengerjaan, dengan tujuan akhir sebagai berikut: - -- Tidak ada izin pengguna yang luas saat penginstalan -- izin tambahan diberikan secara eksplisit oleh pengguna berdasarkan tiap situs. - -- Sepenuhnya delkaratif untuk reliabilitas dan CPU/efisiensi memori. +uBOL sepenuhnya bersifat deklaratif, artinya tidak diperlukan proses uBOL permanen agar penyaringan dapat terjadi, dan penyaringan konten berbasis injeksi CSS/JS dilakukan secara andal oleh browser itu sendiri dan bukan oleh ekstensi. Artinya uBOL sendiri tidak mengonsumsi sumber daya CPU/memori saat pemblokiran konten sedang berlangsung -- proses pekerja layanan uBOL diperlukan _hanya_ saat Anda berinteraksi dengan panel popup atau halaman opsi. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.it.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.it.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.it.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.it.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) è un sistema per bloccare contenuti che *non richiede autorizzazioni* basato su MV3. +uBO Lite (uBOL) è un sistema di blocco dei contenuti basato su MV3. L'insieme di regole predefinito corrisponde all'insieme di filtri predefinito di uBlock Origin: @@ -10,21 +10,3 @@ Puoi abilitare altri set di regole visitando la pagina delle opzioni: clicca sull'icona _Cogs_ nel pannello a comparsa. uBOL è interamente dichiarativo, ovvero non è necessario che ci sia un processo di uBOL permanente per poter eseguire il filtraggio; e il filtraggio dei contenuti basato sull'iniezione di elementi CSS/JS viene eseguito in modo affidabile dal browser stesso piuttosto che dall'estensione. Ciò significa che lo stesso uBOL non consuma risorse di CPU o memoria mentre il blocco dei contenuti viene eseguito: il processo che esegue il servizio di uBOL è richiesto _solamente_ quando interagisci con il pannello a comparsa o con le pagine delle opzioni. - -uBOL non richiede un'ampia autorizzazione di "lettura e modifica dei dati" al momento dell'installazione, da qui le sue capacità limitate rispetto a uBlock Origin o ad altre estensioni che richiedono ampie autorizzazioni di "lettura e modifica dei dati" al momento dell'installazione. - -Tuttavia, uBOL consente di concedere *esplicitamente* permessi estesi a siti specifici di vostra scelta, in modo da poter filtrare meglio tali siti utilizzando il filtraggio cosmetico e le iniezioni di scriptlet. - -Per concedere autorizzazioni estese su un determinato sito, apri il pannello popup e scegli una modalità di filtraggio più elevata come Ottimale o Completa. - -Il browser quindi ti avviserà degli effetti della concessione delle autorizzazioni aggiuntive richieste dall'estensione sul sito corrente e dovrai comunicare al browser se accetti o rifiuti la richiesta. - -Se accetti la richiesta di uBOL per autorizzazioni aggiuntive sul sito corrente, esso sarà in grado di filtrare meglio il contenuto per il sito corrente. - -Puoi impostare la modalità di filtraggio predefinita dalla pagina delle opzioni di uBOL. Se scegli come predefinita la modalità Ottimale o Completa, dovrai concedere a uBOL il permesso di leggere e modificare i dati di tutti i siti web. - -Tieni presente che questo è ancora un work in progress, con questi obiettivi finali: - -- Nessuna autorizzazione estesa degli host al momento dell'installazione; le autorizzazioni estese vengono concesse esplicitamente dall'utente in base al sito. - -- Interamente dichiarativo per l'affidabilità e l'efficienza della CPU/memoria. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ja.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ja.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ja.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ja.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) は権限を必要としない MV3 ベースのコンテンツブロッカーです。 +uBO Lite (uBOL) は MV3 ベースのコンテンツブロッカーです。 デフォルトのルールセットは以下の通りです。uBlock Origin のデフォルトフィルターセットと同じです。 @@ -10,21 +10,3 @@ オプションページでルールセットを有効化できます。ポップアップパネルの「歯車」アイコンをクリックしてください。 uBOL は完全に宣言的です。つまり、フィルタリングを行うための恒久的な uBOL プロセスは必要なく、CSS/JS インジェクション ベースのコンテンツフィルタリングは拡張機能ではなくブラウザによって、確実に実行されます。 これは uBOL がコンテンツブロッキングの際に CPU、メモリを消費しないことを意味します。uBOL のサービス ワーカーは ポップアップ パネルや設定ページでのみ必要とされます。 - -uBOL はインストール時に広範な「データの読み取りと変更」の権限を要求しません。したがって uBlock Origin やその他の、インストール時に広範な「データの読み取りと変更」の権限を要求するコンテンツブロッカーに比べて、行えることが制限されています。 - -しかし、ユーザーの選んだ特定のサイトに対する拡張権限を「明示的に」付与すれば、そのサイト上で整形フィルターやスクリプトレットの挿入を用いた優れたフィルタリングを行うことができます。 - -特定のサイトで拡張された権限を付与するには、ポップアップ パネルを開いて、「最適」や「完全」のようなより高いフィルタリングモードを選択します。 - -ブラウザーは、現在のサイトで拡張機能によってリクエストされた追加の権限を付与することによってもたらされる影響について警告します。承認または拒否することができます。 - -現在のサイトでの uBOL のリクエストを承認すると、現在のサイトにより良いフィルターを適用できるようになります。 - -uBOL の設定ページで既定のフィルタリングモードを設定できます。 「最適」または「完全」を規定のフィルタリング モードに設定した場合、すべてのWebサイトで「データの読み取りと変更」権限を付与する必要があります。 - -注意として、uBOL はまだ開発途中で、これらの開発目標があります。 - -- インストール時に広範なホスト権限は不要 -- 拡張された権限はサイトごとにユーザーによって明示的に付与されます。 - -- 完全に宣言的で、CPU、メモリの効率性が良い diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ka.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ka.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ka.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ka.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,30 +1,12 @@ -uBO Lite (uBOL) *ნებართვებისგან თავისუფალი* MV3-ზე დაფუძნებული შიგთავსის შემზღუდავია. +uBO Lite (uBOL) შიგთავსის შემზღუდავია MV3-ის მიხედვით. წესების ნაგულისხმევი კრებული იგივეა, რასაც uBlock Origin იყენებს: -- uBlock Origin – ფილტრების ჩაშენებული სიები +- ჩაშენებული ფილტრებით, uBlock Origin რომ იყენებს - EasyList - EasyPrivacy - Peter Lowe – სარეკლამო სერვერების სია შეგიძლიათ სხვა კრებულებიც აამოქმედოთ პარამეტრების გვერდიდან -- დაწკაპეთ _Cogs_ ხატულაზე ამომხტომ არეში. -uBOL სრულად დეკლარაციულია, ანუ არაა საჭირო მუდმივად იყოს გაშვებული uBOL-პროცესი გასაფილტრად, CSS/JS ჩანაცვლებით შიგთავსის გაფილტვრას თავად ბრაუზერი უზრუნველყოფს ნაცვლად გაფართოებისა, რაც მეტად საიმედოა. შესაბამისად, uBOL თავად არ დატვირთავს პროცესორს/ოპერატიულს შიგთავსის შეზღუდვის დროს -- uBOL-ის შუამავალი მომსახურე პროცესი საჭიროა _მხოლოდ_ მაშინ, როცა ამომხტომ არესთან ურთიერთქმედებთ ან ცვლით პარამეტრებს. - -uBOL არ საჭიროებს „მონაცემთა წაკითხვისა და შეცვლის“ სრულ ნებართვას დაყენებისას, ვინაიდან მოკვეცილი შესაძლებლობებითაა წარმოდგენილი uBlock Origin-თან ან რეკლამის სხვა შემზღუდავებთან შედარებით, რომლებიც ერთბაშად ითხოვს „მონაცემთა წაკითხვისა და შეცვლის“ უფლებას დაყენებისთანავე. - -ამასთანავე, uBOL საშუალებას გაძლევთ *მკაფიო* თანხმობით მიუთითოთ გაფართოებული ნებართვები ცალკეულ საიტებზე სურვილისამებრ, რომ უკეთ შეიზღუდოს შიგთავსი ხილული ელემენტების გაფილტვრითა და პროგრამული ჩამატებებით. - -გაფართოებული ნებართვების მისაცემად მითითებულ საიტზე, გახსენით ამომხტომი არე და აირჩიეთ ფილტრაციის უფრო მაღალი დონე, როგორიცაა „წონასწორული“ ან „სრული“. - -შემდეგ ბრაუზერი გაგაფრთხილებთ გაფართოების მიერ დამატებითი ნებართვების მოთხოვნის შესახებ მოცემულ საიტზე და აირჩევთ, დათანხმდებით თუ უარყოფთ მოთხოვნას. - -თუ დათანხმდებით uBOL-ს მოთხოვნას დამატებითი ნებართვებისთვის მიმდინარე საიტზე, უკეთ შეძლებს შიგთავსის შეზღუდვას აღნიშნულ საიტზე. - -შეგიძლიათ მიუთითოთ გაფილტვრის ნაგულისხმევი რეჟიმი uBOL-ის პარამეტრების გვერდიდან. თუ აირჩევთ „წონასწორულ“ ან „სრულ“ რეჟიმს ნაგულისხმევად, uBOL-ს უნდა დართოთ ყველა საიტზე მონაცემთა წაკითხვისა და შეცვლის ნება. - -დაიხსომეთ, რომ ჯერ კიდევ მუშავდება შემდეგი მიზნებისთვის: - -- არანაირი სრული ნებართვების ერთბაშად მოთხოვნა დაყენებისას -- დამატებითი უფლებები შეიძლება მიეცეს მომხმარებლის მკაფიო თანხმობით თითოეულ საიტზე ცალ-ცალკე. - -- სრულად დეკლარაციულია პროცესორის/მეხსიერების დასაზოგად. +uBOL მოქმედებს სრულად დადგენილი წესებით, შესაბამისად, არ ესაჭიროება მუდმივად გაშვებული uBOL-პროცესი გასაფილტრად, ხოლო როცა შიგთავსის შეზღუდვა ითხოვს ჩანაცვლდეს CSS/JS, ამას თავად ბრაუზერი უზრუნველყოფს საიმედო გზით, ნაცვლად გაფართოებისა. აქედან გამომდინარე, uBOL თავად არ მოიხმარს პროცესორს/მეხსიერებას შიგთავსის შეზღუდვისას -- uBOL საჭიროებს შუამავალ მომსახურე პროცესს _მხოლოდ_ მაშინ, როცა ამომხტომ არესთან ურთიერთქმედებთ ან ცვლით პარამეტრებს. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.kk.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.kk.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.kk.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.kk.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.kn.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.kn.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.kn.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.kn.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. ಇದರರ್ಥ ವಿಷಯ ನಿರ್ಬಂಧಿಸುವಿಕೆಯು ನಡೆಯುತ್ತಿರುವಾಗ uBOL ಸ್ವತಃ CPU/ಮೆಮೊರಿ ಸಂಪನ್ಮೂಲಗಳನ್ನು ಬಳಸುವುದಿಲ್ಲ -- ನೀವು ಪಾಪ್ಅಪ್ ಪ್ಯಾನೆಲ್ ಅಥವಾ ಆಯ್ಕೆಯ ಪುಟಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಿದಾಗ uBOL ನ ಸೇವಾ ವರ್ಕರ್ ಪ್ರಕ್ರಿಯೆಯು _ಮಾತ್ರಾ_ ಅಗತ್ಯವಿದೆ. - -uBOL ಗೆ ಅನುಸ್ಥಾಪನೆಯ ಸಮಯದಲ್ಲಿ ವಿಶಾಲವಾದ "ಡೇಟಾವನ್ನು ಓದಲು ಮತ್ತು ಮಾರ್ಪಡಿಸಲು" ಅನುಮತಿಯ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ, ಆದ್ದರಿಂದ uBlock ಮೂಲಕ್ಕೆ ಹೋಲಿಸಿದರೆ ಅದರ ಸೀಮಿತ ಸಾಮರ್ಥ್ಯಗಳು ಅಥವಾ ಅನುಸ್ಥಾಪನೆಯ ಸಮಯದಲ್ಲಿ ವಿಶಾಲವಾದ "ಡೇಟಾವನ್ನು ಓದಲು ಮತ್ತು ಮಾರ್ಪಡಿಸಲು" ಅನುಮತಿಗಳ ಅಗತ್ಯವಿರುವ ಇತರ ವಿಷಯ ಬ್ಲಾಕರ್‌ಗಳಿಗೆ ಹೋಲಿಸಿದರೆ. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. ನೀವು ಆಪ್ಟಿಮಲ್ ಅಥವಾ ಕಂಪ್ಲೀಟ್ ಮೋಡ್ ಅನ್ನು ಡಿಫಾಲ್ಟ್ ಆಗಿ ಆರಿಸಿದರೆ, ಎಲ್ಲಾ ವೆಬ್‌ಸೈಟ್‌ಗಳಲ್ಲಿನ ಡೇಟಾವನ್ನು ಓದಲು ಮತ್ತು ಮಾರ್ಪಡಿಸಲು ನೀವು uBOL ಗೆ ಅನುಮತಿಯನ್ನು ನೀಡಬೇಕಾಗುತ್ತದೆ. - -ಈ ಅಂತಿಮ ಗುರಿಗಳೊಂದಿಗೆ ಇದು ಇನ್ನೂ ಪ್ರಗತಿಯಲ್ಲಿದೆ ಎಂಬುದನ್ನು ನೆನಪಿನಲ್ಲಿಡಿ: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ko.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ko.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ko.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ko.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite(uBOL)는 *적은 권한을 요구하는* MV3 기반 콘텐츠 차단기입니다. +uBO Lite (uBOL)는 MV3 기반 콘텐츠 차단기입니다. 기본 규칙 목록은 uBlock Origin의 기본 필터 목록과 대응됩니다. @@ -10,21 +10,3 @@ 설정 페이지에서 규칙 목록을 더 활성화할 수 있습니다. 팝업 창의 _Cogs_ 아이콘을 누르세요. uBOL은 완전히 선언적이라 필터링 중 영구적으로 실행되는 uBOL 프로세스를 필요로 하지 않으며, CSS/JS 주입 기반 콘텐츠 필터링이 확장 프로그램이 아닌 브라우저 자체에서 더욱 안정적으로 동작합니다. 즉 uBOL 자체는 콘텐츠 차단을 하는 동안 CPU/메모리 리소스를 소비하지 않습니다. uBOL 서비스워커 프로세스는 사용자가 팝업 창이나 설정을 열었을 _때에만_ 동작합니다. - -uBOL은 설치 시 광범위한 "읽기 및 수정" 권한을 요구하지 않으므로, 설치 후 즉시 쓸 수 있는 기능들은 uBlock Origin이나 설치 시 광범위한 "읽기 및 수정" 권한을 요구하는 다른 콘텐츠 차단기에 비해 제한됩니다. - -하지만 uBOL에서는 원하는 특정 사이트에 대해 확장된 권한을 부여하여, 해당 사이트를 표면 필터링 및 스크립트 주입을 바탕으로 더욱 잘 필터링할 수 있습니다. - -주어진 사이트에 확장된 권한을 부여하려면, 팝업 창을 열고 필터링 모드를 '최적'이나 '완전'과 같이 더 높은 수준으로 선택하세요. - -브라우저는 확장 프로그램에 현재 사이트에 대한 추가 권한을 부여했을 때 발생할 수 있는 일에 대해 경고할 것이며, 권한 요청을 수락할지 거부할지 선택해야 합니다. - -현재 사이트에 대해 uBOL에 추가 권한을 부여하면, 해당 사이트의 콘텐츠를 더욱 잘 필터링할 수 있습니다. - -uBOL 설정 페이지에서 기본 필터링 모드를 설정할 수 있습니다. 기본 모드를 '최적' 혹은 '완전'으로 설정하는 경우, uBOL에 모든 웹사이트에서 데이터를 읽고 수정할 수 있는 권한을 부여해야 합니다. - -본 확장 프로그램은 여전히 아래 목표를 달성하기 위해 개발 중인 단계입니다. - -- 설치 시 광범위한 호스트 권한을 요구하지 않고, 사용자가 사이트마다 명시적으로 확장된 권한을 부여할 수 있도록 합니다. - -- 완전히 선언적으로 구현하여 CPU/메모리 효율성과 신뢰성을 확보합니다. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.lt.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.lt.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.lt.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.lt.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.lv.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.lv.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.lv.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.lv.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,30 +1,12 @@ -uBO Lite (uBOL) ir *bezatļauju* uz MV3 balstīts satura aizturētājs. +uBO Lite (uBOL) — uz MV3 balstīts satura aizturētājs. -Noklusējuma nosacījumu kopa atbilst uBokc Origin noklusējuma aizturēšanas kopai: +Noklusējuma nosacījumu kopa atbilst uBock Origin noklusējuma aizturēšanas kopai: - uBlock Origin iebūvētie aizturēšanas saraksti - EasyList - EasyPrivacy -- Pētera Lova (Peter Lowe) reklāmu un izsakošanas serveru saraksts +- Pētera Lova (Peter Lowe) reklāmu un izsekošanas serveru saraksts Vairāk nosacījumu kopu var iespējot iestatījumu sadaļā -- jāklikšķina _Zobratu_ ikona uznirstošajā logā. uBOL ir pilnībā vispārīgs, kas nozīmē, ka nav nepieciešamības pēc pastāvīga uBOL procesa, lai notiktu aizturēšana, un uz CSS/JS ievietošanu balstīta satura aizturēšanu uzticami veic pārlūks, nevis paplašinājums. Tas nozīmē, ka uBOL pats par sevi neizmanto procesoru un atmiņu, kamēr satura aizturēšana ir notiekoša -- uBOL pakalpojuma strādņa process ir nepieciešams _tikai_ tad, kad notiek mijiedarbība ar uznirstošo logu vai iestatījumu sadaļām. - -uBOL nav nepieciešamas plašas "lasīt un pārveidot datus" atļaujas uzstādīšanas laikā, tāpēc tam ir ierobežotas spējas pēc noklusējuma, salīdzinājumā ar uBlock Origin vai citiem satura aizturētājiem, kas pieprasa plašas "lasīt un pārveidot datus" atļaujas uzstādīšanas laikā. - -Tomēr uBOL ļauj piešķirt paplašinātās atļaujas *tieši* noteiktās vietnēs pēc izvēles, lai tas varētu labāk veikt aizturēšanu tajās, izmantojot kosmētisku aizturēšanu un skriptu ievietošanu. - -Lai nodrošinātu paplašinātas piekļuves tiesības noteiktā vietnē, jāatver uznirstošais logs un jāizvēlas striktāks aizturēšanas veids, kā, piemēram, "Labākais" vai "Pilnīgais". - -Pārlūks tad brīdinās ietekmi, ko radīs paplašinājuma pieprasīto papildu atļauju nodrošināšana pašreizējā vietnē, un būs jānorāda, vai pieprasījums tiek apstiprināts vai noraidīts. - -Ja pašreizējā vietnē tiek apstiprināts uBOL papildu atļauju pieprasījums, paplašinājums varēs labāk veikt satura aizturēšanu. - -Noklusējuma aizturēšanas veids ir norādāms uBOL uzstādījumu lapā. Ja tiek izvēlēts "Labākais" vai "Pilnīgais" kā noklusējuma, tad būs nepieciešams nodrošināt uBOL tiesības rakstīt un pārveidot datus visās tīmekļa vietnēs. - -Jāpatur prātā, ka šī iespēja joprojām tiek izstrādāta ar šādiem mērķiem: - -- Nav plašu saimniekdatora atļauju uzstādīšanas laikā -- paplašinātas atļaujas nodrošina lietotājs atsevišķi katrai vietnei. - -- Pilnībā vispārīgs - uzticamībai un procesora/atmiņas lietderīgai izmantošanai. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.mk.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.mk.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.mk.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.mk.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) е *без дозвола* MV3-базиран блокатор на содржини. +uBO Lite (uBOL) is an MV3-based content blocker. Стандардниот сет на правила одговара на стандардниот филтер сет на uBlock Origin: @@ -10,21 +10,3 @@ Можете да овозможите повеќе сетови на правила посетувајќи ја страницата со опции - кликнете на иконата _запчаник_ во попап панел. uBOL е целосно декларативен, што значи дека не е потребен траен процес на uBOL за филтрирање да се одвива, а филтрирањето на содржини врз основа на инјекција на CSS/JS се извршува со сигурност од самото браузер, а не од самата екстензија. Ова значи дека самиот uBOL не консумира ресурси на CPU/меморија додека блокирањето на содржини е во тек - процесот на службениот работник на uBOL е потребен _само_ кога ќе е потребен со попап панел или страниците со опции. - -uBOL не бара широка дозвола за „читање и модификување на податоци“ во време на инсталација, па затоа неговите ограничени можности излезат од кутијата во споредба со uBlock Origin или други блокатори на содржини кои бараат широка „читање и модификување на податоци“ дозволи во време на инсталација. - -Сепак, uBOL ви овозможува *експлицитно* да доделите проширени дозволи на специфични страници по ваш избор, така што може подобро да филтрира на тие страници користејќи козметичко филтрирање и инјекции на скрипти. - -За да доделите проширени дозволи на одредена страница, отворете го исфрлениот панел и изберете повисок режим на филтрирање, како што се Оптимален или Комплетен. - -Браузерот ќе ве предупреди за ефектите на задолжителното доделување на дополнителните дозволи кои ги побарала екстензијата на тековната страница, а вие треба да му кажете на браузерот дали ја прифаќате или одбивате побараното. - -Ако ја прифатите побараното од uBOL за дополнителни дозволи на тековната страница, тоа ќе може подобро да филтрира содржина за тековната страница. - -Можете да го поставите подразбираниот режим на филтрирање од страницата со опции на uBOL. Ако ја изберете Оптималната или Комплетната верзија како подразбирана, ќе треба да му овозможите на uBOL дозвола да чита и модифицира податоци на сите веб-страници. - -Имајте на ум дека ова сè уште е работа во тек, со следниве завршни цели: - -- Нема широки хост дозволи при инсталација - проширените дозволи се доделуваат експлицитно од корисникот на основа на секоја страница. - -- Целосно декларативен за сигурност и ефикасност на CPU/меморија. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ml.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ml.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ml.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ml.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) ഒരു *അനുമതി-കുറവ്* MV3 അടിസ്ഥാനമാക്കിയുള്ള ഉള്ളടക്ക ബ്ലോക്കറാണ്. +uBO Lite (uBOL) is an MV3-based content blocker. ഡിഫോൾട്ട് റൂൾസെറ്റ് uBlock Origin-ന്റെ ഡിഫോൾട്ട് ഫിൽട്ടർസെറ്റുമായി യോജിക്കുന്നു: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL പൂർണ്ണമായും ഡിക്ലറേറ്റീവ് ആണ്, അതായത് ഫിൽട്ടറിംഗ് സംഭവിക്കുന്നതിന് ഒരു സ്ഥിരമായ uBOL പ്രക്രിയയുടെ ആവശ്യമില്ല, കൂടാതെ CSS/JS ഇഞ്ചക്ഷൻ അടിസ്ഥാനമാക്കിയുള്ള ഉള്ളടക്ക ഫിൽട്ടറിംഗ്, എക്സ്റ്റൻഷനേക്കാൾ വിശ്വസനീയമായി ബ്രൗസർ തന്നെ നിർവഹിക്കുന്നു. ഉള്ളടക്കം തടയൽ നടന്നുകൊണ്ടിരിക്കുമ്പോൾ uBOL തന്നെ CPU/മെമ്മറി ഉറവിടങ്ങൾ ഉപയോഗിക്കില്ല എന്നാണ് ഇതിനർത്ഥം -- നിങ്ങൾ പോപ്പ്അപ്പ് പാനലുമായോ ഓപ്‌ഷൻ പേജുകളുമായോ സംവദിക്കുമ്പോൾ _only_ uBOL-ന്റെ സേവന വർക്കർ പ്രോസസ്സ് ആവശ്യമാണ്. - -ഇൻസ്റ്റാളേഷൻ സമയത്ത് uBOL ന് വിശാലമായ "ഡാറ്റ വായിക്കാനും പരിഷ്‌ക്കരിക്കാനും" അനുമതി ആവശ്യമില്ല, അതിനാൽ uBlock ഒറിജിൻ അല്ലെങ്കിൽ മറ്റ് ഉള്ളടക്ക ബ്ലോക്കറുകൾ എന്നിവയുമായി താരതമ്യപ്പെടുത്തുമ്പോൾ അതിന്റെ പരിമിതമായ കഴിവുകൾ ഇൻസ്റ്റാളേഷൻ സമയത്ത് വിശാലമായ "ഡാറ്റ വായിക്കാനും പരിഷ്‌ക്കരിക്കാനും" അനുമതികൾ ആവശ്യമാണ്. - -എന്നിരുന്നാലും, നിങ്ങൾ തിരഞ്ഞെടുക്കുന്ന നിർദ്ദിഷ്ട സൈറ്റുകളിൽ വിപുലീകൃത അനുമതികൾ *വ്യക്തമായി* നൽകാൻ uBOL നിങ്ങളെ അനുവദിക്കുന്നു, അതുവഴി കോസ്മെറ്റിക് ഫിൽട്ടറിംഗും സ്ക്രിപ്റ്റ്ലെറ്റ് കുത്തിവയ്പ്പുകളും ഉപയോഗിച്ച് ആ സൈറ്റുകളിൽ മികച്ച രീതിയിൽ ഫിൽട്ടർ ചെയ്യാൻ കഴിയും. - -തന്നിരിക്കുന്ന സൈറ്റിൽ വിപുലമായ അനുമതികൾ നൽകുന്നതിന്, പോപ്പ്അപ്പ് പാനൽ തുറന്ന് ഒപ്റ്റിമൽ അല്ലെങ്കിൽ കംപ്ലീറ്റ് പോലുള്ള ഉയർന്ന ഫിൽട്ടറിംഗ് മോഡ് തിരഞ്ഞെടുക്കുക. - -നിലവിലെ സൈറ്റിൽ വിപുലീകരണം അഭ്യർത്ഥിച്ച അധിക അനുമതികൾ നൽകുന്നതിന്റെ ഫലങ്ങളെക്കുറിച്ച് ബ്രൗസർ നിങ്ങൾക്ക് മുന്നറിയിപ്പ് നൽകും, നിങ്ങൾ അഭ്യർത്ഥന സ്വീകരിക്കുകയോ നിരസിക്കുകയോ ചെയ്യണോ എന്ന് നിങ്ങൾ ബ്രൗസറിനോട് പറയേണ്ടിവരും. - -നിലവിലെ സൈറ്റിൽ കൂടുതൽ അനുമതികൾക്കായുള്ള uBOL-ന്റെ അഭ്യർത്ഥന നിങ്ങൾ അംഗീകരിക്കുകയാണെങ്കിൽ, നിലവിലെ സൈറ്റിനായി മികച്ച ഉള്ളടക്കം ഫിൽട്ടർ ചെയ്യാൻ അതിന് കഴിയും. - -uBOL-ന്റെ ഓപ്‌ഷൻ പേജിൽ നിന്ന് നിങ്ങൾക്ക് ഡിഫോൾട്ട് ഫിൽട്ടറിംഗ് മോഡ് സജ്ജമാക്കാൻ കഴിയും. ഒപ്റ്റിമൽ അല്ലെങ്കിൽ കംപ്ലീറ്റ് മോഡ് ഡിഫോൾട്ടായി നിങ്ങൾ തിരഞ്ഞെടുക്കുകയാണെങ്കിൽ, എല്ലാ വെബ്‌സൈറ്റുകളിലെയും ഡാറ്റ വായിക്കാനും പരിഷ്‌ക്കരിക്കാനും നിങ്ങൾ uBOL-ന് അനുമതി നൽകേണ്ടതുണ്ട്. - -ഈ അന്തിമ ലക്ഷ്യങ്ങളോടെ ഇത് ഇപ്പോഴും പുരോഗമിക്കുന്ന ഒരു ജോലിയാണെന്ന് ഓർമ്മിക്കുക: - -- ഇൻസ്റ്റാളേഷൻ സമയത്ത് ബ്രോഡ് ഹോസ്റ്റ് അനുമതികളൊന്നുമില്ല -- ഓരോ സൈറ്റിന്റെ അടിസ്ഥാനത്തിൽ വിപുലീകൃത അനുമതികൾ ഉപയോക്താവ് വ്യക്തമായി നൽകുന്നു. - -- വിശ്വാസ്യതയ്ക്കും സിപിയു/മെമ്മറി കാര്യക്ഷമതയ്ക്കും പൂർണ്ണമായും പ്രഖ്യാപനം. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.mr.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.mr.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.mr.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.mr.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,30 +1,12 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) हे MV3-आधारित कंटेंट ब्लॉकर आहे. -The default ruleset corresponds to uBlock Origin's default filterset: +डीफॉल्ट नियमसंच uBlock Origin च्या डीफॉल्ट फिल्टरसेटशी संबंधित आहे: -- uBlock Origin's built-in filter lists +- uBlock Origin च्या बिल्ट-इन फिल्टर लिस्ट - EasyList - EasyPrivacy -- Peter Lowe’s Ad and tracking server list +- पीटर लोवची जाहिरात आणि ट्रॅकिंग सर्व्हर यादी -You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. +तुम्ही पर्याय पृष्ठाला भेट देऊन अधिक नियम संच सक्षम करू शकता -- पॉपअप पॅनेलमधील _Cogs_ चिन्हावर क्लिक करा. -uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. +uBOL पूर्णपणे घोषणात्मक आहे, म्हणजे फिल्टरिंगसाठी कायमस्वरूपी uBOL प्रक्रियेची गरज नाही, आणि CSS/JS इंजेक्शनवर आधारित सामग्री फिल्टरिंग ब्राउझरच्याच मदतीने विश्वासार्हपणे होते, विस्ताराद्वारे नव्हे. याचा अर्थ असा की सामग्री ब्लॉकिंग चालू असताना uBOL स्वतः CPU/मेमरी संसाधने वापरत नाही — uBOL चा सर्व्हिस वर्कर प्रोसेस फक्त तेव्हाच लागतो जेव्हा तुम्ही पॉपअप पॅनल किंवा पर्याय पृष्ठांशी संवाद साधता. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ms.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ms.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ms.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ms.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) ialah penyekat kandungan berasaskan MV3. +uBO Lite (uBOL) is an MV3-based content blocker. Set peraturan lalai sepadan dengan set penapis lalai uBlock Origin: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL adalah deklaratif sepenuhnya, bermakna tidak ada keperluan untuk proses uBOL kekal untuk penapisan berlaku, dan penapisan kandungan berasaskan suntikan CSS/JS dilakukan sepenuhnya oleh penyemak imbas itu sendiri dan bukannya oleh sambungan. Ini bermakna uBOL sendiri tidak menggunakan sumber CPU/memori semasa penyekatan kandungan sedang berjalan -- proses pekerja perkhidmatan uBOL diperlukan _hanya_ apabila anda berinteraksi dengan panel timbul atau halaman pilihan. - -uBOL tidak memerlukan kebenaran "baca dan ubah suai data" yang luas pada masa pemasangan, oleh itu keupayaan terhadnya di luar kotak berbanding dengan uBlock Origin atau penyekat kandungan lain yang memerlukan kebenaran "baca dan ubah suai data" yang luas pada masa pemasangan. - -Walau bagaimanapun, uBOL membenarkan anda *dengan jelas* memberikan kebenaran lanjutan pada tapak tertentu pilihan anda supaya ia boleh menapis dengan lebih baik pada tapak tersebut menggunakan penapisan kosmetik dan suntikan skrip. - -Untuk memberikan kebenaran lanjutan pada tapak tertentu, buka panel timbul dan pilih mod penapisan yang lebih tinggi seperti Optimum atau Lengkap. - -Penyemak imbas kemudian akan memberi amaran kepada anda tentang kesan pemberian kebenaran tambahan yang diminta oleh sambungan pada tapak semasa dan anda perlu memberitahu penyemak imbas sama ada anda menerima atau menolak permintaan tersebut. - -Jika anda menerima permintaan uBOL untuk mendapatkan kebenaran tambahan pada tapak semasa, ia akan dapat menapis kandungan dengan lebih baik untuk tapak semasa. - -Anda boleh menetapkan mod penapisan lalai dari halaman pilihan 'uBOL'. Jika anda memilih mod Optimum atau Lengkap sebagai mod lalai, anda perlu memberikan uBOL kebenaran untuk membaca dan mengubah suai data pada semua tapak web. - -Perlu diingat bahawa ini masih dalam proses, dengan matlamat akhir ini: - -- Tiada kebenaran hos pada masa pemasangan -- kebenaran lanjutan diberikan secara eksplisit oleh pengguna pada asas setiap tapak. - -- Deklaratif sepenuhnya untuk kebolehpercayaan dan kecekapan CPU/memori. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.nb.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.nb.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.nb.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.nb.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) er en *tillatelses-begrenset* MV3-basert innholdsblokkerer. +uBO Lite (uBOL) er en MV3-basert innholdsblokkerer. Standardregelsettet tilsvarer standardfiltersettet til uBlock Origin: @@ -7,24 +7,6 @@ - EasyPrivacy - Peter Lowe’s Ad and tracking server list -You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. +Du kan legge til flere regelsett ved å gå til innstillingssiden -- klikk _Tannhjul_-ikonet i oppsprettspanelet. uBOL er fullstendig deklarativ, noe som betyr at det ikke er behov for en permanent uBOL-prosess for at filtreringen skal skje, og CSS/JS-injeksjonsbasert innholdsfiltrering utføres pålitelig av nettleseren selv i stedet for av utvidelsen. Dette betyr at uBOL selv ikke bruker CPU/minneressurser mens innholdsblokkering pågår -- uBOL's service worker-prosess kreves _bare_ når du samhandler med oppsprettspanelet eller innstillingssidene. - -uBOL krever ikke bred "lese og endre data"-tillatelse under installasjonen, derav begrensede muligheter i utgangspunktet sammenlignet med uBlock Origin eller andre innholdsblokkerere som krever bred "lese og endre data"-tillatelse under installasjonen. - -Men, uBOL lar deg *uttrykkelig* gi utvidede tillatelser på bestemte nettsteder du velger, slik at uBOL bedre kan filtrere på disse nettstedene ved bruk av kosmetisk filtrering og skriptlet-injeksjoner. - -For å gi utvidede tillatelser på et gitt nettsted, åpne oppsprettspanelet og velg en høyere filtreringsmodus som Optimal eller Fullstendig. - -Nettleseren vil da advare deg om effektene av å gi de ekstra tillatelsene som utvidelsen ber om på det gjeldende nettstedet, og du må fortelle nettleseren om du godtar eller avslår forespørselen. - -Hvis du godtar forespørselen fra uBOL om ekstra tillatelser på det gjeldende nettstedet, vil uBOL være i stand til å filtrere innhold bedre for det gjeldende nettstedet. - -Du kan angi standard filtreringsmodus fra innstillingssiden i uBOL. Hvis du velger Optimal eller Fullstendig modus som standard, må du gi uBOL tillatelsen til å lese og endre data på alle nettsteder. - -Husk at dette fortsatt er et arbeid som pågår, med disse sluttmålene: - -- Ingen brede vertstillatelser under installasjonen -- utvidede tillatelser gis uttrykkelig av brukeren på per-side-basis. - -- Helt deklarativt for pålitelighet og CPU/minneeffektivitet. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.nl.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.nl.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.nl.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.nl.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is een *toestemmingsloze* MV3-gebaseerde inhoudsblokkeerder. +uBO Lite (uBOL) is een op MV3 gebaseerde inhoudsblokkeerder. De standaard regelset komt overeen met de standaard filterset van uBlock Origin: @@ -10,21 +10,3 @@ U kunt meer regelsets inschakelen door de optiespagina te bezoeken -- klik hiervoor op het _tandwielpictogram_ in het pop-uppaneel. uBOL is volledig declaratief, wat betekent dat er geen permanent uBOL-proces voor de filtering nodig is, en inhoudsfiltering op basis van CSS/JS-injectie op een betrouwbare manier door de browser zelf wordt uitgevoerd in plaats van door de extensie. Dit betekent dat uBOL zelf geen CPU-/geheugenbronnen gebruikt terwijl inhoudsblokkering actief is -- het serviceworker-proces van uBOL is _alleen_ vereist als u met het pop-uppaneel of de optiespagina’s werkt. - -uBOL vereist geen brede toestemming voor het ‘lezen en aanpassen van gegevens’ tijdens installatie, vandaar de beperkte ingebouwde mogelijkheden ervan in vergelijking met uBlock Origin of andere inhoudsblokkeerders die brede toestemmingen voor het ‘lezen en aanpassen van gegevens’ vereisen tijdens installatie. - -U kunt in uBOL echter *expliciet* uitgebreide toestemmingen verlenen op bepaalde websites van uw keuze, zodat het op die websites beter kan filteren via cosmetische filtering en scriptlet-injecties. - -Om uitgebreide toestemmingen op een bepaalde website te verlenen, opent u het pop-uppaneel en kiest u een hogere filtermodus, zoals Optimaal of Volledig. - -De browser waarschuwt u dan over de gevolgen van het verlenen van de door de extensie aangevraagde aanvullende toestemmingen op de huidige website, en u dient de browser te laten weten of u de aanvraag accepteert of weigert. - -Als u de aanvraag van uBOL voor aanvullende toestemmingen op de huidige website accepteert, zal het inhoud voor de huidige website beter kunnen filteren. - -U kunt de standaard filtermodus instellen vanaf de optiespagina van uBOL. Als u de modus Optimaal of Volledig als de standaardmodus kiest, dient u uBOL de toestemming voor het lezen en aanpassen van gegevens op alle websites te verlenen. - -Onthoud dat dit nog werk in uitvoering is, met deze einddoelen: - -- Geen brede host-toestemmingen tijdens installatie -- uitgebreide toestemmingen worden expliciet en per website verleend door de gebruiker. - -- Volledig declaratief omwille van betrouwbaarheid en CPU-/geheugenefficiëntie. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.oc.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.oc.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.oc.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.oc.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.pa.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.pa.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.pa.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.pa.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) ਇੱਕ *ਬਿਨਾਂ ਇਜਾਜ਼ਤਾਂ* ਵਾਲਾ MV3-ਅਧਾਰਿਤ ਸਮੱਗਰੀ ਬਲਾਕਰ ਹੈ। +uBO Lite (uBOL) is an MV3-based content blocker. ਮੂਲ ਨਿਯਮ-ਸਮੂਹ uBlock Origin ਦੇ ਮੂਲ ਫਿਲਟਰ-ਸਮੂਹ ਨਾਲ ਸੰਬੰਧਿਤ ਹੈ: @@ -10,21 +10,3 @@ ਤੁਸੀਂ ਚੋਣਾਂ ਸਫ਼ੇ ਨੂੰ ਖੋਲ੍ਹ ਕੇ ਹੋਰ ਰੂਲ-ਸੈੱਟ ਸਮਰੱਥ ਕਰ ਕਦੇ ਹੋ -- ਪੌਪ-ਅੱਪ ਪੈਨਲ ਵਿੱਚ _Cogs_ icon ਨੂੰ ਕਲਿੱਕ ਕਰੋ। uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -ਜੇ ਤੁਸੀਂ ਮੌਜੂਦਾ ਸਾਈਟਾਂ ਉੱਤੇ ਹੋਰ ਇਜਾਜਤਾਂ ਲਈ uBOL ਦੀ ਬੇਨਤੀ ਨੂੰ ਮਨਜ਼ੂਰ ਕੀਤਾ ਤਾਂ ਇਹ ਮੌਜੂਦਾ ਸਾਈਟ ਬਾਰੇ ਵਧੀਆ ਫਿਲਟਰ ਸਮੱਗਰੀ ਨੂੰ ਸਮਰੱਥ ਕਰੇਗੀ। - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -ਯਾਦ ਰੱਖੋ ਕਿ ਇਹ ਕੰਮ ਹਾਲੇ ਵੀ ਜਾਰੀ ਹੈ, ਜਿਸ ਦੇ ਟੀਚੇ ਇਹ ਹਨ: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.pl.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.pl.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.pl.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.pl.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) to *niewymagający uprawnień* bloker treści oparty na MV3. +uBO Lite (uBOL) to bloker treści oparty na MV3. Domyślny zestaw reguł odpowiada domyślnemu zestawowi filtrów uBlock Origin: @@ -10,21 +10,3 @@ Możesz włączyć więcej zestawów reguł, odwiedzając stronę opcji – kliknij ikonę _koła zębatego_ w wyskakującym panelu. uBOL jest całkowicie deklaratywny, co oznacza, że nie jest potrzebny stały proces uBOL w celu filtrowania, a filtrowanie treści oparte na wstrzykiwaniu CSS/JS jest wykonywane niezawodnie przez samą przeglądarkę, a nie przez rozszerzenie. Oznacza to, że sam uBOL nie zużywa zasobów procesora/pamięci, gdy trwa blokowanie treści – proces Service Worker uBOL jest wymagany _tylko_ podczas interakcji z panelem wyskakującym lub stronami opcji. - -uBOL w trakcie instalacji nie wymaga szerokich uprawnień do „odczytu i modyfikacji danych”, stąd jego ograniczone możliwości w porównaniu z uBlock Origin lub innymi blokerami treści, które w czasie instalacji wymagają szerokich uprawnień do „odczytu i modyfikacji danych”. - -Jednakże uBOL umożliwia *jawnie* udzielanie rozszerzonych uprawnień na określonych wybranych witrynach, dzięki czemu może lepiej filtrować te witryny za pomocą filtrowania kosmetycznego i wstrzykiwania skryptletów. - -Aby przyznać rozszerzone uprawnienia na danej witrynie, otwórz panel wyskakujący i wybierz wyższy tryb filtrowania, taki jak Optymalny lub Kompletny. - -Przeglądarka wyświetli ostrzeżenie o skutkach przyznania dodatkowych uprawnień wymaganych przez rozszerzenie na bieżącej witrynie i będziesz musiał poinformować przeglądarkę, czy akceptujesz, czy odrzucasz żądanie. - -Jeśli zaakceptujesz żądanie uBOL o dodatkowe uprawnienia na bieżącej witrynie, będzie on w stanie lepiej filtrować zawartość bieżącej witryny. - -Możesz ustawić domyślny tryb filtrowania na stronie opcji uBOL. Jeśli tryb Optymalny lub Pełny zostanie wybrany jako domyślny, trzeba będzie przyznać uBOL uprawnienia do odczytu i modyfikacji danych na wszystkich stronach internetowych. - -Należy pamiętać, że nadal trwają prace z następującymi celami końcowymi: - -– Brak szerokich uprawnień hosta w czasie instalacji – rozszerzone uprawnienia są przyznawane jawnie przez użytkownika na podstawie poszczególnych witryn. - -– Całkowicie deklaratywna niezawodność i wydajność procesora/pamięci. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.pt_BR.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.pt_BR.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.pt_BR.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.pt_BR.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,30 +1,12 @@ -O uBO Lite (uBOL) é um bloqueador de conteúdo baseado no MV3 com menor permissão. +O uBO Lite (uBOL) é um bloqueador de conteúdo baseado no MV3. O conjunto de regras padrão corresponde ao conjunto de filtros padrão do uBlock Origin: - Listas embutidas dos filtros do uBlock Origin - EasyList - EasyPrivacy -- Lista de servidores de anúncios e rastreadores do Peter Lowe +- Lista de servidores de anúncios e rastreamento por Peter Lowe -Você pode ativar mais conjuntos de regras visitando a página das opções — clique no ícone da _Engranagem_ no painel do popup. +Você pode ativar mais conjuntos de regras visitando a página de opções — clique no ícone da _Engranagem_ no painel do pop-up. -O uBOL é totalmente declarativo, significando que não há necessidade de um processo permanente do uBOL para a filtragem ocorrer e a filtragem de conteúdo baseada em injeção do CSS/JS é realizada confiavelmente pelo próprio navegador ao invés da extensão. Isto significa que o próprio uBOL não consome recursos de CPU/memória enquanto o bloqueio de conteúdo está em andamento -- o processo do service worker do uBOL _só_ é necessário quando você interage com o painel do pop-up ou as páginas das opções. - -O uBOL não requer permissão ampla pra "ler e modificar dados" na hora da instalação, logo suas capacidades limitadas fora da caixa comparadas com o uBlock Origin ou outros bloqueadores de conteúdo requerem permissões amplas pra "ler e modificar dados" na hora da instalação. - -Contudo, o uBOL permite a você garantir *explicitamente* permissões estendidas em sites específicos de sua escolha pra que possa filtrar melhor esses sites usando filtragem cosmética e injeções de scriptlet. - -Pra conceder permissões estendidas num site dado, abra o painel do pop-up e escolha um modo de filtragem superior tal como Otimizado ou Completo. - -O navegador então avisará você sobre os efeitos de garantir as permissões adicionais requisitadas pela extensão no site atual e você terá que dizer ao navegador se você aceita ou recusa a requisição. - -Se você aceitar a requisição do uBOL por permissões adicionais no site atual ele será capaz de filtrar melhor o conteúdo do site atual. - -Você pode definir o modo de filtragem padrão na página de opções do uBOL. Se você escolher o Modo Otimizado ou Completo como o modo padrão você precisará garantir ao uBOL a permissão de ler e modificar os dados em todos os sites. - -Mantenha em mente que este ainda é um trabalho em progresso com estes objetivos finais: - -- Sem permissões amplas do hospedeiro na hora da instalação -- as permissões estendidas são garantidas explicitamente pelo usuário numa base por site. - -- Totalmente declarativo para confiabilidade e eficiência de CPU/memória. +O uBOL é totalmente declarativo, significando que não há necessidade de um processo permanente do uBOL para a filtragem ocorrer, e filtragem de conteúdo baseada em injeção de CSS/JS é realizada corretamente pelo próprio navegador ao invés da extensão. Isto significa que o uBOL em si não consome recursos de CPU/memória ao bloquear conteúdo -- o processo do service worker do uBOL _só_ é necessário quando você interage com o painel do pop-up ou as páginas de opções. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.pt_PT.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.pt_PT.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.pt_PT.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.pt_PT.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,30 +1,12 @@ -O uBO Lite (uBOL) é um bloqueador de conteúdo baseado no MV3 *sem permissões*. +O uBO Lite (uBOL) é um bloqueador de conteúdo baseado em MV3. -O conjunto de regras padrão corresponde ao conjunto de filtros padrão do uBlock Origin: +O conjunto de regras predefinido corresponde ao conjunto de filtros predefinido do uBlock Origin: - Listas de filtros integrados do uBlock Origin - EasyList - EasyPrivacy - Peter Lowe’s Ad and tracking server list -Pode ativar mais conjuntos de regras visitando a página de opções -- clique no ícone _Cogs_ na janela flutuante. +Pode ativar mais conjuntos de regras visitando a página de opções -- clique no ícone _Cogs_ no painel popup. -O uBOL é totalmente declarativo, o que elimina a necessidade de um processo ativo constante para a filtragem ocorrer. A injeção de CSS e JS para filtragem de conteúdo é efetuada de maneira confiável pelo navegador, não dependendo da extensão. Isso significa que o uBOL por si só não gasta recursos de CPU/memória enquanto o bloqueio de conteúdo está a acontecer -- o processo do trabalhador de serviço do uBOL é necessário apenas quando se interage com a janela flutuante ou as páginas de opções. - -uBOL não requer ampla permissão de "ler e modificar dados" no momento da instalação, daí as suas capacidades limitadas de pronto a usar em comparação com uBlock Origin ou outros bloqueadores de conteúdo que requerem amplas permissões de "ler e modificar dados" no momento da instalação. - -No entanto, o uBOL permite-lhe que *explicitamente* conceda permissões alargadas em websites específicos de sua escolha, para que possa filtrar melhor esses websites usando filtragem cosmética e injeções de scriptlet. - -Para conceder permissões alargadas num determinado sítio web, abra a janela flutuante e escolha um modo de filtragem superior, como 'Ideal' ou 'Completo'. - -O navegador irá avisá-lo sobre os efeitos da concessão das permissões adicionais solicitadas pela extensão no site atual, e terá que informar ao navegador se aceita ou recusa o pedido. - -Se aceitar o pedido do uBOL para permissões adicionais no site atual, o mesmo poderá filtrar melhor o conteúdo do site atual. - -Pode definir o modo de filtragem padrão na página de opções do uBOL. Se escolher o modo Ideal ou Completo como o modo predefinido, terá de conceder ao uBOL a permissão para ler e modificar dados em todos os sítios web. - -Tenha em mente que este ainda é um trabalho em curso, com estes objetivos finais: - -- Sem permissões amplas de anfitrião no momento da instalação -- permissões estendidas são concedidas explicitamente pelo utilizador numa base por site. - -- Totalmente declarativo para fiabilidade e eficiência de CPU/memória +O uBOL é totalmente declarativo, o que significa que não é necessário um processo permanente do uBOL para que a filtragem ocorra, e a filtragem de conteúdos baseada em injeção de CSS/JS é realizada de forma fiável pelo próprio navegador, e não pela extensão. Isto significa que o próprio uBOL não consome recursos de CPU/memória enquanto o bloqueio de conteúdo está ativo -- o processo do service worker do uBOL é necessário apenas quando interage com o painel popup ou com as páginas de opções. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ro.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ro.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ro.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ro.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,30 +1,12 @@ -uBO Lite (uBOL) este blocant de conținut experimental *fără permisiuni* bazat pe MV3. +uBO Lite (uBOL) este un blocker de conținut bazat pe MV3. Setul de reguli implicit corespunde setului de filtre implicit al uBlock Origin: Listele de filtre încorporate de uBlock Origin - EasyList - EasyPrivacy -- Oglas Peter Lowe i lista servera za praćenje +- -Lista de servere de anunț și de urmărire a lui Peter Lowe -You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. +Puteți activa mai multe seturi de reguli accesând pagina de opțiuni - faceți clic pe pictograma _Cogs_ din panoul pop-up. uBOL este în întregime declarativ, ceea ce înseamnă că nu este nevoie de un proces uBOL permanent pentru ca filtrarea să aibă loc, iar filtrarea conținutului pe bază de injecție CSS/JS este realizată în mod sigur de browser în sine, mai degrabă decât de extensie. Aceasta înseamnă că uBOL în sine nu consumă resurse CPU/memorie în timp ce blocarea conținutului este în desfășurare -- procesul de lucru al serviciului uBOL este necesar _doar_ atunci când interacționați cu panoul pop-up sau cu paginile de opțiuni. - -uBOL nu necesită permisiunii extinse de „citire și modificare a datelor” în momentul instalării, astfel capacitățile sale limitate din momentul instalării în comparație cu uBlock Origin sau alte blocare de conținut necesită permisiuni largi de „citire și modificare a datelor” în momentul instalării. - -Cu toate acestea, uBOL vă permite să acordați *explicit* permisiuni extinse pe anumite site-uri alese de dvs., astfel încât să poată filtra mai bine pe acele site-uri folosind filtrarea cosmetică și injecțiile de scriptlet. - -Pentru a acorda permisiuni extinse pe un anumit site, deschideți panoul pop-up și alegeți un mod de filtrare mai ridicat, cum ar fi Optimal sau Complet. - -Browser-ul vă va avertiza apoi cu privire la efectele acordării permisiunilor suplimentare solicitate de extensie pe site-ul curent și va trebui să-i precizați browserului dacă acceptați sau refuzați cererea. - -Dacă acceptați solicitarea uBOL pentru permisiuni suplimentare pe site-ul curent, acesta va putea filtra mai bine conținutul pentru site-ul curent. - -Puteți seta modul implicit de filtrare din pagina de opțiuni a uBOL. Dacă alegeți modul optim sau complet ca implicit, va trebui să acordați lui uBOL permisiunea de a citi și modifica datele de pe toate site-urile web. - -Rețineți că aceasta este în curs de desfășurare, cu aceste obiective finale: - -- Fără permisiuni de gazdă largi în momentul instalării - permisiunile extinse sunt acordate în mod explicit de către utilizator pe bază de site. - -- Complet declarativ pentru fiabilitate și eficiență CPU/memorie. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ru.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ru.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ru.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ru.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) — это блокировщик содержимого, *не требующий разрешений*, и основанный на MV3. +uBO Lite (uBOL) — это блокировщик веб-элементов на базе MV3. Стандартный набор правил соответствует типовому набору фильтров uBlock Origin: @@ -10,21 +10,3 @@ Вы можете активировать больше списков правил на странице настроек -- нажмите на значок _Шестерёнки_ на всплывающей панели. uBOL - полностью декларативный, т.е. для фильтрации не нужен постоянно выполняющийся uBOL процесс, а фильтрация контента, основанная на внедрении CSS/JS, производится непосредственно браузером. Это значит, что дополнение uBOL не расходует ресурсы ЦПУ/памяти, когда происходит блокировка рекламы -- служебный процесс uBOL запускается, _только_ когда вы вносите изменения на всплывающей панели или странице настроек. - -uBOL не требует разрешение на полное "чтение и изменение данных" в момент установки, поэтому имеет ограниченные возможности по сравнению с uBlock Origin, и другими блокировщиками контента, которые требуют полное разрешение на "чтение и изменение данных" в момент установки. - -Однако uBOL позволяет *намеренно* давать расширенные разрешения для определенных сайтов - по вашему усмотрению, чтобы эффективнее работать, используя косметическую фильтрацию и scriptlet-внедрения. - -Для предоставления расширенных разрешений на текущем сайте - откройте всплывающую панель и выберите повышенный режим фильтрации: Оптимальный или Полный. - -Далее браузер выдаст предупреждение об эффектах предоставления расширенных разрешений, запрошенных дополнением на текущем сайте, и надо будет выбрать: принять или отклонить этот запрос. - -Если вы принимаете запрос uBOL на предоставление дополнительных разрешений, тогда дополнение сможет эффективнее фильтровать контент на текущем сайте. - -Вы можете установить стандартный режим фильтрации на странице настроек uBOL. Если вы выбираете Оптимальный или Полный режим - режимом по умолчанию, необходимо предоставить uBOL разрешение на чтение и изменение данных на всех веб-сайтах. - -Помните, что данный проект - в активной фазе разработки, преследующей следующие цели: - -- Работа с ограниченными разрешениями при установке -- расширенные разрешения пользователь выдает по своему усмотрению, каждому сайту отдельно. - -- Полностью декларативная работа - для надежности и эффективного использования ЦПУ/памяти. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.si.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.si.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.si.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.si.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,30 +1,12 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) යනු MV3-පාදක අන්තර්ගත අවහිර කරන්නා වේ. -The default ruleset corresponds to uBlock Origin's default filterset: +පෙරනිමි රීති කට්ටලය uBlock Origin හි පෙරනිමි පෙරහන් කට්ටලයට අනුරූප වේ: -- uBlock Origin's built-in filter lists -- EasyList -- EasyPrivacy -- Peter Lowe’s Ad and tracking server list +- uBlock Origin හි බිල්ට් පෙරහන් ලැයිස්තු +- පහසු ලැයිස්තුව +- පහසු පෞද්ගලිකත්වය +- පීටර් ලෝගේ දැන්වීම් සහ ලුහුබැඳීමේ සේවාදායක ලැයිස්තුව -You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. +විකල්ප පිටුවට පිවිසීමෙන් ඔබට තවත් නීති කට්ටල සක්‍රීය කළ හැකිය -- උත්පතන පැනලයේ _Cogs_ නිරූපකය ක්ලික් කරන්න. -uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. +uBOL සම්පූර්ණයෙන්ම ප්‍රකාශනාත්මකයි, එනම් පෙරීම සිදුවීමට ස්ථිර uBOL ක්‍රියාවලියක් අවශ්‍ය නොවන අතර, CSS/JS එන්නත්-පාදක අන්තර්ගත පෙරීම දිගුව මගින් නොව බ්‍රවුසරය විසින්ම විශ්වාසදායක ලෙස සිදු කරයි. මෙයින් අදහස් කරන්නේ අන්තර්ගත අවහිර කිරීම සිදුවෙමින් පවතින අතරතුර uBOL විසින්ම CPU/මතක සම්පත් පරිභෝජනය නොකරන බවයි -- ඔබ උත්පතන පැනලය හෝ විකල්ප පිටු සමඟ අන්තර් ක්‍රියා කරන විට uBOL හි සේවා සේවක ක්‍රියාවලිය _only_ අවශ්‍ය වේ. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.sk.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.sk.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.sk.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.sk.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) je blokovač obsahu založený na MV3 *bez povolenia*. +uBO Lite (uBOL) je blokovač obsahu založený na MV3. Predvolený súbor pravidiel zodpovedá predvolenému súboru filtrov uBlock Origin: @@ -10,21 +10,3 @@ Ďalšie súbory pravidiel môžete povoliť na stránke s možnosťami – kliknite na ikonu _súkolesia_ vo vyskakovacom paneli. uBOL je úplne deklaratívny, čo znamená, že na filtrovanie nie je potrebný trvalý proces uBOL a filtrovanie obsahu založené na injektovaní CSS/JS spoľahlivo vykonáva samotný prehliadač, a nie rozšírenie. To znamená, že samotný uBOL nespotrebúva zdroje CPU/pamäte, kým prebieha blokovanie obsahu -- proces uBOL Service Worker je potrebný _len_ pri interakcii s vyskakovacím panelom alebo stránkami možností. - -uBOL pri inštalácii nevyžaduje všeobecné oprávnenie "čítať a upravovať údaje", preto má obmedzené možnosti v porovnaní s uBlock Origin alebo inými blokovačmi obsahu, ktoré pri inštalácii vyžadujú všeobecné oprávnenie "čítať a upravovať údaje". - -uBOL vám však umožňuje *výslovne* udeliť všebecné oprávnenia na konkrétne stránky podľa vášho výberu, aby mohol lepšie filtrovať na týchto stránkach pomocou kozmetického filtrovania a injektovaných skriptletov. - -Ak chcete udeliť všeobecné oprávnenia na danom webe, otvorte vyskakovací panel a vyberte vyšší režim filtrovania, napríklad Optimálny alebo Kompletný. - -Prehliadač vás potom upozorní na dôsledky udelenia dodatočných oprávnení požadovaných rozšírením na aktuálnej stránke a vy budete musieť prehliadaču oznámiť, či požiadavku prijímate alebo odmietate. - -Ak prijmete žiadosť uBOL o dodatočné povolenia na aktuálnom webe, bude môcť lepšie filtrovať obsah aktuálneho webu. - -Predvolený režim filtrovania môžete nastaviť na stránke možností uBOL. Ak ako predvolený režim vyberiete Optimálny alebo Kompletný režim, budete musieť uBOL-u udeliť oprávnenie na čítanie a úpravu údajov na všetkých webových stránkach. - -Majte na pamäti, že na tomto projekte sa stále pracuje, pričom jeho konečné ciele sú takéto: - -- Žiadne všeobecné oprávnenia hostiteľa v čase inštalácie -- rozšírené oprávnenia udeľuje používateľ explicitne pre jednotlivé stránky. - -- Úplne deklaratívne pre spoľahlivosť a efektivitu CPU/pamäte. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.sl.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.sl.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.sl.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.sl.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.so.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.so.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.so.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.so.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.sq.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.sq.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.sq.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.sq.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) është një bllokues *i pavarur* që funksionon sipas modelit MV3. +uBO Lite (uBOL) është një bllokues materialesh sipas modelit MV3. Rregullat e tij janë të barasvlershme me filtrat standardë që përdor uBlock Origin: @@ -10,21 +10,3 @@ Në faqen e opsioneve mund të aktivizoni rregulla të tjera – klikoni ikonën e _ingranazhit_ në panelin modal. uBOL është tërësisht deklarativ, domethënë filtrimi ndodh pa qenë nevoja që procesi i uBOL të vijojë vazhdimisht në sfond, ndërsa injektimi i filtrave CSS/JS te materialet kryhet me saktësi nga vetë shfletuesi. Pra, uBOL i bllokon materialet pa konsumuar resurset e procesorit/memories – asetet e uBOL nevojiten _vetëm_ kur ndërveproni me panelin modal ose faqen e opsioneve të tij. - -uBO Lite nuk kërkon leje shtesë për "leximin dhe modifikimin e të dhënave" kur e instaloni, prandaj fillimisht ka aftësi më të kufizuara sesa uBlock Origin apo bllokuesit e tjerë që kërkojnë leje shtesë për "leximin dhe modifikimin e të dhënave" gjatë instalimit. - -Megjithatë ju mund t'i jepni uBOL leje të posaçme *eksplicite* për ato uebsajte që doni, në mënyrë që t'i filtrojë më mirë me filtra kozmetikë dhe skripte. - -Lejet e posaçme për uebsajtet jepen nëpërmjet panelit modal duke zgjedhur mënyrën e filtrimit Optimal ose Komplet. - -Më tej shfletuesi do ju informojë për efektet e dhënies së këtyre lejeve për uebsajtin në fjalë dhe ju duhet ta pranoni ose refuzoni kërkesën. - -Po ta pranoni dhënien e lejeve shtesë për uebsajtin në fjalë, uBOL do mundet ta filtrojë më mirë atë. - -Në faqen e opsioneve të uBOL mund të përcaktoni mënyrën standarde të filtrimit. Nëse vendosni si standard mënyrën Optimale ose Komplete, uBOL do ju marrë leje për leximin dhe modifikimin e të dhënave në të gjitha uebsajtet. - -Kini parasysh se ky projekt është në zhvillim e sipër sipas këtyre objektivave: - -- Instalohet pa leje shtesë – lejet e posaçme për çdo uebsajt jepen në mënyrë eksplicite nga përdoruesi. - -- Tërësisht deklarativ për të qenë më i qëndrueshëm dhe eficient me procesorin/memorien. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.sr.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.sr.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.sr.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.sr.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) је блокатор садржаја *без дозвола*, заснован на MV3. +uBO Lite (uBOL) је блокатор садржаја заснован на MV3. Подразумевани скуп правила одговара подразумеваном скупу филтера uBlock Origin-а: @@ -10,21 +10,3 @@ Можете омогућити још скупова правила тако што ћете посетити страницу са опцијама -- кликните на иконицу зупчаника у искачућем панелу. uBOL је потпуно декларативан, што значи да нема потребе за трајним uBOL процесом да би дошло до филтрирања, а филтрирање садржаја засновано на убацивању CSS/JS се обавља поуздано од стране самог прегледача, а не проширења. То значи да сам uBOL не троши CPU/меморијске ресурсе док је блокирање садржаја у току -- сервисни радни процес uBOL-а је потребан _само_ када ступите у интеракцију са искачућим панелом или страницама опција. - -uBOL не захтева широку дозволу за „читање и измену података” у тренутку инсталације, стога су његове ограничене могућности ван оквира у поређењу са uBlock Origin-ом или другим блокаторима садржаја који захтевају широке дозволе за „читање и измену података” у тренутку инсталације. - -Међутим, uBOL вам омогућује да *експлицитно* доделите проширене дозволе на одређеним сајтовима по вашем избору тако да може боље да филтрира те сајтове користећи козметичко филтрирање и ињекције скриптлета. - -Да бисте доделили проширене дозволе за дати сајт, отворите искачући панел и изаберите виши режим филтрирања, као што је Оптимално или Комплетно. - -Прегледач ће вас тада упозорити на ефекте давања додатних дозвола које захтева проширење на тренутном сајту, а ви ћете морати да кажете прегледачу да ли прихватате или одбијате захтев. - -Ако прихватите uBOL-ов захтев за додатне дозволе на тренутном сајту, он ће моћи боље да филтрира садржај за тренутни сајт. - -Можете подесити подразумевани режим филтрирања на uBOL-овој страници са опцијама. Ако изаберете режим Оптимално или Комплетно као подразумевани, мораћете да доделите uBOL-у дозволу да чита и мења податке на свим веб сајтовима. - -Имајте на уму да је ово још увек рад у току, са овим крајњим циљевима: - -– Нема широких дозвола за хост у тренутку инсталације – проширене дозволе се експлицитно додељују од стране корисника на основу сваког сајта. - -- Потпуно декларативан за поузданост и ефикасност CPU/меморије. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.sv.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.sv.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.sv.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.sv.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) är en *behörighetslös* MV3-baserad innehållsblockerare. +uBO Lite (uBOL) är en MV3-baserad innehållsblockerare. Standardregeluppsättningen motsvarar uBlock Origins standardfilteruppsättning: @@ -10,21 +10,3 @@ Du kan lägga till fler regeluppsättningar i alternativ -- klicka på _Kugghjulet_ i popup-panelen. uBOL är helt deklarativt, vilket innebär att det inte finns något behov av en permanent uBOL-process för att filtreringen ska ske och CSS/JS-injektionsbaserad innehållsfiltrering utförs på ett tillförlitligt sätt av webbläsaren själv snarare än av tillägget. Detta innebär att uBOL själv inte förbrukar CPU/minnesresurser medan innehållsblockering pågår -- uBOLs serviceworkerprocess krävs _endast_ när du interagerar med popup-panelen eller alternativsidorna. - -uBOL kräver inte högre behörighet för "läs och ändra data" vid installationen, därav dess begränsade möjligheter jämfört med uBlock Origin eller andra innehållsblockerare som kräver högre behörighet för "läs och ändra data" vid installationen. - -Däremot låter uBOL dig *uttryckligen* ge utökade behörigheter på specifika webbplatser du väljer så att den bättre kan filtrera på dessa webbplatser med hjälp av kosmetisk filtrering och scriptletinjektioner. - -För att ge utökade behörigheter på en viss webbplats, öppna popup-panelen och välj ett högre filtreringsläge som optimal eller fullständig. - -Webbläsaren kommer sedan att varna dig om effekterna av att bevilja de ytterligare behörigheter som tillägget begär på den aktuella webbplatsen och du måste tala om för webbläsaren om du accepterar eller avslår begäran. - -Om du accepterar uBOLs begäran om ytterligare behörigheter på den aktuella webbplatsen kommer den att kunna filtrera innehåll för den aktuella webbplatsen bättre. - -Du kan ställa in standardfiltreringsläget från uBOLs alternativsida. Om du väljer läge optimalt eller fullständigt som standard måste du ge uBOL behörighet att läsa och ändra data på alla webbplatser. - -Tänk på att detta fortfarande är ett pågående arbete med dessa slutmål: - -- Inga högre värdbehörigheter vid installationen - utökade behörigheter ges uttryckligen av användaren per webbplats. - -- Helt deklarativt för tillförlitlighet och CPU/minneseffektivitet. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.sw.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.sw.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.sw.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.sw.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ta.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ta.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ta.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ta.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.te.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.te.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.te.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.te.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) అనేది *అనుమతి-తక్కువ* MV3-ఆధారిత కంటెంట్ బ్లాకర్. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOLకి ఇన్‌స్టాల్ సమయంలో విస్తృత "డేటాను చదవడం మరియు సవరించడం" అనుమతి అవసరం లేదు, అందువల్ల uBlock ఆరిజిన్ లేదా ఇన్‌స్టాల్ సమయంలో విస్తృతమైన "డేటాను చదవడం మరియు సవరించడం" అనుమతులు అవసరమయ్యే ఇతర కంటెంట్ బ్లాకర్‌లతో పోలిస్తే దాని పరిమిత సామర్థ్యాలు బాక్స్ వెలుపల ఉన్నాయి. - -అయితే, uBOL మీకు నచ్చిన నిర్దిష్ట సైట్‌లలో పొడిగించిన అనుమతులను *స్పష్టంగా* మంజూరు చేయడానికి మిమ్మల్ని అనుమతిస్తుంది, తద్వారా కాస్మెటిక్ ఫిల్టరింగ్ మరియు స్క్రిప్ట్‌లెట్ ఇంజెక్షన్‌లను ఉపయోగించి ఆ సైట్‌లలో మెరుగ్గా ఫిల్టర్ చేయవచ్చు. - -ఇచ్చిన సైట్‌లో పొడిగించిన అనుమతులను మంజూరు చేయడానికి, పాప్‌అప్ ప్యానెల్‌ను తెరిచి, ఆప్టిమల్ లేదా కంప్లీట్ వంటి అధిక ఫిల్టరింగ్ మోడ్‌ను ఎంచుకోండి. - -ప్రస్తుత సైట్‌లో పొడిగింపు ద్వారా అభ్యర్థించిన అదనపు అనుమతులను మంజూరు చేయడం వల్ల కలిగే ప్రభావాల గురించి బ్రౌజర్ మిమ్మల్ని హెచ్చరిస్తుంది మరియు మీరు అభ్యర్థనను అంగీకరించాలా లేదా తిరస్కరించాలా అని మీరు బ్రౌజర్‌కి తెలియజేయాలి. - -మీరు ప్రస్తుత సైట్‌లో అదనపు అనుమతుల కోసం uBOL అభ్యర్థనను అంగీకరిస్తే, అది ప్రస్తుత సైట్ కోసం కంటెంట్‌ను మెరుగ్గా ఫిల్టర్ చేయగలదు. - -మీరు uBOL ఎంపికల పేజీ నుండి డిఫాల్ట్ ఫిల్టరింగ్ మోడ్‌ను సెట్ చేయవచ్చు. మీరు డిఫాల్ట్‌గా ఆప్టిమల్ లేదా కంప్లీట్ మోడ్‌ని ఎంచుకుంటే, మీరు అన్ని వెబ్‌సైట్‌లలోని డేటాను చదవడానికి మరియు సవరించడానికి uBOLకి అనుమతిని మంజూరు చేయాలి. - -ఈ తుది లక్ష్యాలతో ఇది ఇంకా పురోగతిలో ఉందని గుర్తుంచుకోండి: - -- ఇన్‌స్టాల్ సమయంలో విస్తృత హోస్ట్ అనుమతులు లేవు -- పొడిగించిన అనుమతులు ప్రతి-సైట్ ప్రాతిపదికన వినియోగదారు ద్వారా స్పష్టంగా మంజూరు చేయబడతాయి. - -- విశ్వసనీయత మరియు CPU/మెమరీ సామర్థ్యం కోసం పూర్తిగా డిక్లరేటివ్. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.th.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.th.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.th.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.th.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,30 +1,12 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) คือตัวบล็อกเนื้อหาที่ใช้สถาปัตยกรรม MV3 -The default ruleset corresponds to uBlock Origin's default filterset: +ชุดเงื่อนไขเริ่มต้นสอดคล้องกันกับค่าตัวกรองเริ่มต้นของ uBlock Origin: -- uBlock Origin's built-in filter lists +- รายการตัวกรองภายใน uBlock Origin - EasyList - EasyPrivacy -- Peter Lowe’s Ad and tracking server list +- รายการติดตามเซิร์ฟเวอร์โฆษณาของ Peter Lowe -You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. +คุณสามารถเปิดใช้งานชุดกฎเพิ่มเติมได้โดยไปที่หน้าตั้งค่า -- คลิกที่ไอคอนรูปเฟือง (Cogs) ในหน้าต่างป๊อปอัป -uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. +uBOL ทำงานในรูปแบบเชิงประกาศ (declarative) ทั้งหมด ซึ่งหมายความว่าไม่จำเป็นต้องมีโพรเซสถาวรของ uBOL สำหรับการกรอง และการกรองเนื้อหาที่อาศัยการฉีดโค้ด CSS/JS จะถูกดำเนินการอย่างมีเสถียรภาพโดยตัวเบราว์เซอร์เอง แทนที่จะทำโดยส่วนขยาย นั่นหมายความว่าตัว uBOL เองจะไม่ใช้ทรัพยากร CPU และหน่วยความจำในขณะที่การบล็อกเนื้อหากำลังทำงาน -- โพรเซส Service Worker ของ uBOL จะถูกเรียกใช้เฉพาะเมื่อคุณใช้งานหน้าต่างป๊อปอัปหรือหน้าตั้งค่าเท่านั้น diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.tr.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.tr.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.tr.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.tr.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL), *izin gerektirmeyen* MV3 tabanlı bir içerik engelleyicidir. +uBO Lite (uBOL), MV3 tabanlı bir içerik engelleyicidir. Varsayılan kural seti, uBlock Origin'in varsayılan filtre setine karşılık gelir: @@ -10,21 +10,3 @@ Seçenekler ekranına uğrayarak daha fazla kuralı aktif hale getirebilirsiniz, bunun için açılır paneldeki _dişli_ simgesine tıklayın. uBOL tamamen bildirimseldir, yani filtrelemenin gerçekleşmesi için kalıcı bir uBOL işlemine gerek yoktur, içerik filtreleme eklenti yerine tarayıcının kendisi tarafından CSS/JS yerleştirerek gerçekleştirilir. Bu, içerik engelleme devam ederken uBOL'nin kendisinin CPU/bellek kaynaklarını tüketmediği anlamına gelir -- uBOL'un hizmet çalışanı işlemi, _only_ açılan panel veya seçenek sayfalarıyla etkileşim kurduğunuzda gereklidir. - -uBOL, kurulum sırasında geniş "veri okuma ve değiştirme" izni gerektirmez, bu nedenle, kurulum sırasında geniş "veri okuma ve değiştirme" izinleri gerektiren uBlock Origin veya diğer içerik engelleyicilere kıyasla, kutudan çıkar çıkmaz sınırlı yetenekleri vardır. - -Bununla birlikte, uBOL, kozmetik filtreleme ve komut dosyası enjeksiyonları kullanarak bu sitelerde daha iyi filtre uygulayabilmesi için, seçtiğiniz belirli sitelerde *açıkça* genişletilmiş izinler vermenize izin verir. - -Belirli bir sitede genişletilmiş izinler vermek için açılır paneli açın ve Optimal veya Complete gibi daha yüksek bir filtreleme modu seçin. - -Ardından tarayıcı, uzantı tarafından istenen ek izinlerin geçerli sitede verilmesinin etkileri konusunda sizi uyaracak ve tarayıcıya isteği kabul edip etmediğinizi söylemeniz gerekecektir. - -uBOL'un mevcut site için ek izin talebini kabul ederseniz, mevcut site için içeriği daha iyi filtreleyebilecektir. - -Varsayılan filtreleme modunu uBOL'un seçenekler sayfasından ayarlayabilirsiniz. Varsayılan mod olarak Optimal veya Complete modunu seçerseniz, uBOL'a tüm web sitelerindeki verileri okuma ve değiştirme izni vermeniz gerekecektir. - -Bunun, şu nihai hedeflerle hala devam eden bir çalışma olduğunu unutmayın: - -- Yükleme sırasında geniş ana bilgisayar izinleri yoktur -- genişletilmiş izinler, her site için kullanıcı tarafından açıkça verilir. - -- Güvenilirlik ve CPU/bellek verimliliği için tamamen bildirimsel. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.uk.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.uk.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.uk.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.uk.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) - це блокувальник вмісту на основі MV3, що не потребує дозволів. +uBO Lite (uBOL) - це блокувальник вмісту на основі MV3. Набір правил за замовчанням відповідає типовому набору фільтрів uBlock Origin: @@ -10,21 +10,3 @@ Ви можете ввімкнути більше наборів правил, перейшовши на сторінку налаштувань — натисніть на піктограму "Перейти до панелі керування" на спливній панелі. uBOL повністю декларативний, тобто немає необхідності в постійному процесі uBOL для здійснення фільтрації, а фільтрація вмісту на основі CSS/JS-ін'єкцій надійно виконується самим браузером, а не розширенням. Це означає, що сам uBOL не споживає ресурси процесора/пам'яті під час блокування вмісту — службовий робочий процес uBOL потрібен _лише_ під час взаємодії зі спливною панеллю або сторінками опцій. - -uBOL не вимагає широкого дозволу на «читання та зміну даних» під час встановлення, отже, його можливості «з коробки» обмежені порівняно з uBlock Origin або іншими блокувальниками, які вимагають широкого дозволу на «читання/зміну даних» під час встановлення. - -Однак uBOL дозволяє вам *явно* надавати розширені дозволи на певних сайтах на ваш вибір, щоб він міг краще виконувати фільтрування на цих сайтах, використовуючи косметичну фільтрацію та вкладення скриптів. - -Щоб надати розширені дозволи на певному сайті, відкрийте спливну панель і виберіть вищий режим фільтрації, наприклад, «Оптимальний» або «Повний». - -Потім браузер попередить вас про наслідки надання додаткових дозволів, запитуваних розширенням, на поточному сайті, і ви повинні будете повідомити браузеру, чи приймаєте ви запит або відхиляєте його. - -Якщо ви приймете запит uBOL на додаткові дозволи на поточному сайті, він зможе краще фільтрувати вміст для цього сайту. - -Ви можете типовий налаштувати режим фільтрації на сторінці налаштувань uBOL. Якщо ви обираєте типовим режим Оптимальний або Повний, вам потрібно буде надати uBOL дозвіл на читання та зміну даних на всіх вебсайтах. - -Варто пам'ятати, що це досі незавершена робота з такими цілями: - -- Відсутність широких дозволів на хост під час встановлення — розширені дозволи надаються користувачем окремо для кожного сайту. - -- Повністю декларативна оцінка надійності та ефективності роботи процесора/пам'яті. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ur.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ur.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.ur.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.ur.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) ایک *اجازت سے کم* MV3 پر مبنی مواد بلاکر ہے۔ +uBO Lite (uBOL) is an MV3-based content blocker. ڈیفالٹ رولسیٹ uBlock Origin کے ڈیفالٹ فلٹر سیٹ سے مساوی ہے: @@ -10,21 +10,3 @@ You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.vi.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.vi.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.vi.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.vi.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) là trình chặn nội dung dựa trên MV3 *không-cần-cấp-phép*. +uBO Lite (uBOL) là trình chặn nội dung dựa trên MV3. Bộ quy tắc mặc định tương tự bộ lọc của uBlock Origin: @@ -10,21 +10,3 @@ Bạn có thể tự thêm quy tắc mới ở trang cài đặt -- click vào biểu tượng _Bánh răng_ ở trong cửa sổ popup. uBOL mang tính khai báo hoàn toàn, vì vậy uBOL sẽ không cần phải liên tục chạy để chặn nội dung. Thay vào đó, chính trình duyệt sẽ thực hiện lọc nội dung bằng cách sử dụng công cụ chèn CSS/JS hiệu quả hơn có sẵn của nó. Điều này cũng đồng thời có nghĩa là uBOL sẽ không tiêu tốn tài nguyên CPU/bộ nhớ của bạn để chặn nội dung. uBOL sẽ chỉ chạy _khi và chỉ khi_ bạn đang xem cửa sổ popup của uBOL, hoặc bạn đang cấu hình uBOL ở trang cài đặt. - -uBOL không yêu cầu cấp quyền "đọc và sửa đổi dữ liệu" chung khi cài đặt, vì vậy nên ban đầu nó sẽ hơi yếu hơn uBlock Origin hoặc các trình chặn nội dung khác mà có yêu cầu quyền "đọc và sửa đổi dữ liệu" chung khi cài đặt. - -Tuy nhiên, uBOL lại cho phép bạn cấu hình *rất cụ thể* quyền ở trên bất kỳ trang nào tự chọn của bạn, để nó có thể lọc nội dụng trên các trang đấy tốt hơn bằng các kỹ thuật như lọc hiển thị (cosmetic filtering) hay chèn kịch bản con (scriptlet injections). - -Để cấp quyền cho uBOL chặn trang bất kỳ, hãy mở cửa sổ popup và chọn một chế độ chặn cao hơn như "Tối ưu" hoặc "Hoàn toàn". - -Trình duyệt của bạn sẽ hiện cảnh báo cho việc cấp quyền cho tiện ích trên trang web hiện tại, và bạn sẽ phải chọn đồng ý hoặc từ chối yêu cầu cấp quyền. - -Nếu bạn chọn đồng ý cấp quyền cho uBOL sửa trang web bất kỳ, uBOL sẽ có thể lọc nội dung tốt hơn cho web đấy. - -Bạn cũng có thể chọn chế độ chặn mặc định ở trang cài đặt của uBOL. Nếu bạn chọn chế độ Tối ưu hoặc Hoàn toàn làm mặc định, bạn sẽ cần phải cấp quyền "đọc và sửa đổi dữ liệu" trên tất cả các trang web. - -Lưu ý rằng sản phẩm này vẫn đang trong giai đoạn phát triển, và bản hoàn thiện sẽ có những tính năng sau: - -- Không yêu cầu bất kỳ quyền nào khi cài đặt - người dùng sẽ phải tự chủ động cấp bất kỳ quyền gì cho tiện ích, cụ thể từng trang web một. - -- Hoàn toàn mang tính khai báo, để có thế chạy nhẹ hơn và ổn định hơn. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.zh_CN.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.zh_CN.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.zh_CN.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.zh_CN.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,30 +1,12 @@ -uBO Lite (uBOL) 是一个基于最新浏览器扩展接口(Manifest Version 3)打造的“无需权限”的内容屏蔽工具。 +uBO Lite (uBOL) 是一个基于最新浏览器扩展接口(Manifest Version 3)打造的的内容屏蔽工具。 该扩展预设的规则列表对应 uBlock Origin 的预设过滤规则列表: - uBlock Origin 内置过滤规则列表 - EasyList - EasyPrivacy -- Peter Lowe’s Ad and tracking server list +- Peter Lowe 的广告和跟踪服务器列表 -访问选项页面,点击弹出面板中的齿轮图标,即可启用更多规则集。 +访问选项页面,点击弹出面板中的 _齿轮_ 图标,即可启用更多规则集。 -uBOL 的过滤规则是完全声明式的,并不需要固定保留一个 uBOL 扩展进程,基于 CSS/JS 注入的内容过滤更是交由浏览器进行调度,比起扩展本身更为可靠。 这也即是说当内容被过滤时 uBOL 自身并不占用额外 CPU 和内存资源,只有在您打开弹出面板或是设置页面时才会生成 uBOL 扩展进程。 - -uBOL 在安装时并不需要宽泛的“读取或修改网页数据”的权限,因此它的开箱即用功能相对于 uBlock Origin 以及其他安装时要求该权限的屏蔽工具显得较为有限。 - -不过,uBOL 可在您“明确”授予额外扩屏权限后,对您指定的网站采用基于 CSS/JS 注入的声明式规则加强内容过滤。 - -若要在特定网站授予扩展权限,请开启弹出面板并选择更高级的过滤模式,例如“优化”或“完全”。 - -接着浏览器会就在当前网站授予扩展额外权限有何影响示以警告,而您要接受或者拒绝该请求。 - -如果您允许 uBOL 在当前网站获取额外权限,它就可以更好地对网站内容进行过滤。 - -您还可以在 uBOL 的设置页面设定默认过滤模式。 如果设定的默认过滤模式是“优化”或“完全”,您必须授予 uBOL 读取或修改所有网页数据的权限。 - -请注意,该扩展尚未完成,其最终实现目标是: - -- 安装时不需要过多扩展权限——额外权限要由用戶指定,按需求及作用域授予。 - -- 采用完全声明式规则,以求可靠性以及更佳 CPU 和内存使用效率。 +uBOL 的过滤规则是完全声明式的,并不需要固定保留一个 uBOL 扩展进程,基于 CSS/JS 注入的内容过滤更是交由浏览器进行调度,比起扩展本身更为可靠。 这也即是说当内容被过滤时 uBOL 自身并不占用额外 CPU 和内存资源,_只有_在您打开弹出面板或是设置页面时才会生成 uBOL 扩展进程。 diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.zh_TW.txt ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.zh_TW.txt --- ublock-origin-1.62.0+dfsg/platform/mv3/description/webstore.zh_TW.txt 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/description/webstore.zh_TW.txt 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,4 @@ -uBO Lite (uBOL) 是款以 MV3 為基礎的「免權限」內容阻擋器。 +uBO Lite (uBOL) 是一個基於 MV3 的內容封鎖器。 預設規則集對應着 uBlock Origin 的預設過濾集: @@ -10,21 +10,3 @@ 您可以前往選項頁面(按下彈出面板的 **齒輪** 按鈕)啟用更多規則集。 uBOL 是完全宣告式的,意即過濾過程中不需要持續性的 uBOL 處理程序參與,且以 CSS/JS 注入為基礎的內容過濾由可靠的瀏覽器執行,而非是擴充功能。 這就代表 uBOL 在內容阻擋過程不會佔用 CPU 和記憶體資源——除了和彈出面板或選項頁面互動的場景外,都不需要 uBOL 的 Service Worker 程序。 - -uBOL 在安裝期間不需要廣泛的「讀取與修改資料」權限,因此它出廠時的功能和 uBlock Origin 或其他在安裝期間要求該權限的內容阻擋程式相比,相對受限。 - -不過 uBOL 能讓你 **明確地** 在自選的特定網站授予額外的權限,使其在這些網站的過濾效果可以在元素過濾及 scripetlet 注入的加持下提升。 - -若要授予指定網站延伸權限,請開啟彈出面板並選擇更佳的過濾模式,如「最佳」或「完整」。 - -瀏覽器接著會警告您授予擴充功能請求的額外權限所帶來的後果,而你需要告訴瀏覽器要同意還是拒絕。 - -如果你接受 uBOL 在目前網站請求的額外權限,其在這個網站的過濾效果將會更好。 - -您可以在 uBOL 的選項頁面設定預設的過濾模式。 如果您選擇「最佳」或「完整」為預設模式,您需要授予 uBOL 讀取與修改所有網站資料的權限。 - -注意這尚未完工,最終目標有: - -- 安裝期間不要有氾濫的 host 權限 —— 以網站為基準讓使用者授予延伸權限。 - -- 完全宣告式,以提升可靠性和 CPU / 記憶體效率。 diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/edge/patch-extension.js ublock-origin-1.67.0+dfsg/platform/mv3/edge/patch-extension.js --- ublock-origin-1.62.0+dfsg/platform/mv3/edge/patch-extension.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/edge/patch-extension.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,71 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2022-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import fs from 'fs/promises'; +import process from 'process'; + +/******************************************************************************/ + +const commandLineArgs = (( ) => { + const args = Object.create(null); + let name, value; + for ( const arg of process.argv.slice(2) ) { + const pos = arg.indexOf('='); + if ( pos === -1 ) { + name = arg; + value = ''; + } else { + name = arg.slice(0, pos); + value = arg.slice(pos+1); + } + args[name] = value; + } + return args; +})(); + +/******************************************************************************/ + +async function main() { + const packageDir = commandLineArgs.packageDir; + const manifestPath = `${packageDir}/manifest.json`; + + // Get manifest content + const manifest = await fs.readFile(manifestPath, { encoding: 'utf8' + }).then(text => + JSON.parse(text) + ); + + // https://learn.microsoft.com/answers/questions/918426/cant-update-extension-with-declarative-net-request + // Set all ruleset path to package root + for ( const ruleset of manifest.declarative_net_request.rule_resources ) { + const pos = ruleset.path.lastIndexOf('/'); + if ( pos === -1 ) { continue; } + ruleset.path = ruleset.path.slice(pos + 1); + } + // Commit changes + await fs.writeFile(manifestPath, + JSON.stringify(manifest, null, 2) + ); +} + +main(); + +/******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ar/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ar/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ar/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ar/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,11 +4,11 @@ "description": "extension name." }, "extShortDesc": { - "message": "أداة لحظر المحتوى دون إذن. يحظر الإعلانات وأدوات التتبع وأدوات التعدين وغيرها فور التثبيت.", + "message": "أداة فعالة لحجب المحتوى. تحجب الإعلانات والمتتبعين والمعدنين وغير ذلك فور تثبيتها.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { - "message": "{{ruleCount}} قواعد، محولة من {{filterCount}} مرشحات الشبكة", + "message": "{{ruleCount}} قواعد، محولة من {{filterCount}} فلاتر الشبكة", "description": "Appears aside each filter list in the _3rd-party filters_ pane" }, "dashboardName": { @@ -19,6 +19,14 @@ "message": "الإعدادات", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "فلاتر مخصصة", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "تطوير", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "حول البرنامج", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "وضع التصفية", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "على هذا الموقع", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "الإبلاغ عن مشكلة في هذا الموقع", "description": "Tooltip used for the 'chat' icon in the panel" @@ -60,7 +72,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "نطاقات البرامج الضارة", + "message": "الحماية من البرامج الضارة، الأمان", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -75,12 +87,20 @@ "message": "المناطق واللغات", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "استيراد / تصدير", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "الصق هنا فلاتر تجميلية محددة لإضافتها", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "سجل التغييرات", "description": "" }, "aboutCode": { - "message": "شفرة المصدر (GPLv3)", + "message": "كود المصدر (GPLv3)", "description": "English: Source code (GPLv3)" }, "aboutContributors": { @@ -88,7 +108,7 @@ "description": "English: Contributors" }, "aboutSourceCode": { - "message": "شيفرة المصدر", + "message": "كود المصدر", "description": "Link text to source code repo" }, "aboutTranslations": { @@ -96,7 +116,7 @@ "description": "Link text to translations repo" }, "aboutFilterLists": { - "message": "قوائم التصفية", + "message": "قوائم الفلاتر", "description": "Link text to uBO's own filter lists repo" }, "aboutDependencies": { @@ -104,13 +124,17 @@ "description": "Shown in the About pane" }, "supportS6H": { - "message": "الإبلاغ عن مشكلة في عوامل التصفية", + "message": "الإبلاغ عن مشكلة في الفلاتر", "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS3P1": { - "message": "الإبلاغ عن مشكلات الفلترة الخاصة بمواقع الويب المحددة إلىuBlockOrigin/uAssetsمتتبع المشكلةيتطلب حساب GitHub", + "message": "الإبلاغ عن مشكلات التصفية الخاصة بمواقع الويب المحددة إلىuBlockOrigin/uAssetsمتتبع المشكلةيتطلب حساب GitHub", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "معلومات استكشاف وإصلاح الأخطاء", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { "message": "لتجنب تحميل المتطوعين بتقارير مكررة، يرجى التأكد من أن المشكلة لم يتم الإبلاغ عنها بالفعل.", "description": "A paragraph in the filter issue reporter section" @@ -120,11 +144,11 @@ "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { - "message": "عنوان صفحة الويب", + "message": "عنوان صفحة الويب:", "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "صفحة الويب...", + "message": "صفحة الويب…", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { @@ -136,7 +160,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "يحتوي على تراكبات أو إزعاجات أخرى.", + "message": "يحتوي على تراكبات أو إزعاجات أخرى", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { @@ -148,15 +172,15 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "تعطل عند تفعيل uBO Lite.", + "message": "تعطل عند تفعيل uBO Lite", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { - "message": "يفتح علامات تبويب أو نوافذ غير مرغوب فيها.", + "message": "يفتح علامات تبويب أو نوافذ غير مرغوب فيها", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { - "message": "يؤدي إلى البرامج الضارة والإحتيال", + "message": "يؤدي إلى برامج ضارة وتصيد احتيالي", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { @@ -164,23 +188,15 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "إنشاء تقرير جديد", + "message": "إنشاء تقرير جديد علي GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "مرحبا", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "لقد قمت للتو بتثبيت uBO Lite. هنا يمكنك اختيار وضع التصفية الافتراضي لاستخدامه في جميع مواقع الويب.\n\nبشكل افتراضي ، يتم تحديد الوضع الأساسي لأنه لا يتطلب الإذن لقراءة البيانات وتعديلها. إذا كنت تثق في uBO Lite ، فيمكنك منحه إذنًا واسعًا لقراءة البيانات وتعديلها على جميع مواقع الويب من أجل تمكين المزيد من إمكانات التصفية المتقدمة لجميع مواقع الويب افتراضيًا.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "وضع التصفية الافتراضي", "description": "The header text for the default filtering mode section" }, "defaultFilteringModeDescription": { - "message": "سيتم تجاوز وضع التصفية الافتراضي بواسطة أوضاع التصفية لكل موقع ويب. يمكنك ضبط وضع التصفية على أي موقع ويب معين وفقًا للوضع الذي يعمل بشكل أفضل على موقع الويب هذا. كل وضع له مزاياه وعيوبه.", + "message": "سيتم تجاوز وضع التصفية الافتراضي بواسطة أوضاع التصفية الخاصة بكل موقع ويب. يمكنك ضبط وضع التصفية على أي موقع ويب وفقًا للوضع الذي يعمل بشكل أفضل على ذلك الموقع. لكل وضع مزاياه وعيوبه.", "description": "This describes the default filtering mode setting" }, "filteringMode0Name": { @@ -212,11 +228,11 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "قائمة بأسماء المضيفين التي لن تتم أي تصفية لها", + "message": "قائمة المواقع الإلكترونية التي لن يتم تصفية محتواها.", "description": "A short description for the editable field which lists trusted sites" }, "noFilteringModePlaceholder": { - "message": "[أسماء النطاقات الرئيسية فقط]\nexample.com\ngames.example", + "message": "[أسماء النطاقات الرئيسية فقط]\nexample.com\ngames.example\n...", "description": "Default text for in edit field" }, "behaviorSectionLabel": { @@ -236,9 +252,29 @@ "description": "Label for a checkbox in the options page" }, "enableStrictBlockLegend": { - "message": "سيتم حظر التنقل إلى المواقع غير المرغوب فيها، وسيتم تقديم خيار لك للمتابعة.", + "message": "سيتم حظر الانتقال إلى المواقع غير المرغوب فيها، وسيُعرض عليك خيار المتابعة.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "وضع المطور", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "يتيح الوصول إلى الميزات المناسبة للمستخدمين التقنيين.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "النسخ الاحتياطي", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "قم بنسخ الإعدادات المخصصة احتياطيًا إلى ملف، أو استعادة الإعدادات المخصصة من ملف.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "ستؤدي عملية الاستعادة إلى استبدال جميع إعداداتك المخصصة الحالية.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "البحث عن القوائم", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "متابعة", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "إزالة عنصر", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "خروج من وضع مزيل العناصر", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "أنشئ تصفية مخصّصة", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "أزِل التصفية المخصّصة", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "عرض:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "تفاصيل وضع التصفية", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "قواعد DNR مخصصة", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "قواعد DNR لـ …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "مجموعة قواعد متغيرة", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "مجموعة قواعد جَلسة", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "حفظ", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "إرجاع", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "أضِف", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "استيراد وإلحاق…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "تصدير…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "نسخ احتياطي…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "استعادة…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "لا تضف محتوى من مصادر غير موثوقة", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "عدد القواعد المسجلة: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "حرك الشريط لتحديد أفضل تطابق", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "اختيار", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "معاينة", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "إنشاء", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "اختر تصفية أدناه لتمييز العناصر المطابقة في صفحة الويب. انقر على سلة المهملات لإزالة التصفية.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/az/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/az/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/az/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/az/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Tənzimləmələr", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Haqqında", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Report an issue", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Bölgələr, dillər", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Dəyişikliklər siyahısı", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Xoş gəldiniz", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/be/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/be/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/be/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/be/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -8,7 +8,7 @@ "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { - "message": "{{ruleCount}} правілаў, пераўтвораных з {{filterCount}} сеткавых фільтраў", + "message": "Правілы (колькасць: {{ruleCount}}), якія пераўтвораны з сеткавых фільтраў (колькасць: {{filterCount}})", "description": "Appears aside each filter list in the _3rd-party filters_ pane" }, "dashboardName": { @@ -19,6 +19,14 @@ "message": "Налады", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Уласныя фільтры", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Распрацоўка", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Пра пашырэнне", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "рэжым фільтравання", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "На гэтым сайце", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "Паведаміць пра праблему на гэтым вэб-сайце", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "Рэгіёны, мовы", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Імпартаваць/экспартаваць", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Журнал змяненняў", "description": "" @@ -111,6 +131,10 @@ "message": "Паведамляйце пра праблемы з фільтрамі, датычныя канкрэтных вэб-сайтаў, праз трэкер праблемuBlockOrigin/uAssets . Патрэбны ўліковы запіс GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Дыягнастычныя звесткі", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { "message": "Каб не абцяжарваць добраахвотнікаў дубляванымі справаздачамі, калі ласка, пераканайцеся, што пра гэтую праблему не паведамлялі раней.", "description": "A paragraph in the filter issue reporter section" @@ -128,7 +152,7 @@ "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { - "message": "-- Выберыце тэму --", + "message": "-- Выберыце праблему --", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { @@ -167,14 +191,6 @@ "message": "Стварыць новую справаздачу", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Вітаем", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Вы толькі што ўсталявалі uBO Lite. Тут вы можаце выбраць прадвызначаны рэжым фільтравання для ўсіх вэб-сайтаў.\n\nКалі не ўказана іншае, выбраны базавы рэжым, бо ён не патрабуе дазволаў на чытанне і змяненне звестак. Калі вы давяраеце uBO Lite, можаце даць яму шырэйшыя дазволы на чытанне і змяненне звестак на ўсіх вэб-сайтах, каб зрабіць магчымымі больш прасунутыя функцыі фільтравання прадвызначана на ўсіх вэб-сайтах.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Прадвызначаны рэжым фільтравання", "description": "The header text for the default filtering mode section" @@ -216,7 +232,7 @@ "description": "A short description for the editable field which lists trusted sites" }, "noFilteringModePlaceholder": { - "message": "[толькі назвы хостаў]\nexample.com\ngames.example\n...", + "message": "[толькі назвы вузлоў]\nexample.com\ngames.example\n...", "description": "Default text for in edit field" }, "behaviorSectionLabel": { @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Пераход да патэнцыйна непажаданых сайтаў будзе заблакаваны, і вам будзе прапанавана магчымасць працягнуць.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Рэжым распрацоўніка", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Забяспечвае доступ да функцый, прыдатным для тэхнічных карыстальнікаў.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Знайсці спісы", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Працягнуць", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Перайсці ў рэжым імгненнага хавання элементаў", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Выйсці з рэжыму імгненнага хавання элементаў", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Стварыць уласны фільтр", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Выдаліць уласны фільтр", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Выгляд", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Падрабязныя звесткі аб рэжыме фільтрацыі", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Уласныя правілы DNR", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Правілы у DNR", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Дынамічны набор правілаў", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Набор правілаў сеансу", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Захаваць", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Вярнуць", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Дадаць", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Імпартаваць ды дадаць…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Экспартаваць…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Не дадавайце кантэнт з ненадзейных крыніц", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Колькасць зарэгістраваных правілаў: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Перасуньце паўзунок, каб выбраць найлепшы варыянт", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Выбраць", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Папярэдні прагляд", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Стварыць", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Выберыце фільтр ніжэй, каб вылучыць адпаведныя элементы на старонцы. Націсніце на кошык, каб выдаліць фільтр.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/bg/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/bg/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/bg/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/bg/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Настройки", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Персонализирани филтри", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Разработка", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Относно", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "режим на филтриране", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "На този уебсайт", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "Докладване на проблем с този уебсайт", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "Региони, езици", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Импортиране / експортиране", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Поставете тук конкретни козметични филтри, които искате да добавите", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Списък с промени", "description": "" @@ -111,6 +131,10 @@ "message": "Докладвайте за проблеми с филтрирането на конкретни уебсайтове в uBlockOrigin/uAssets за проследяване на проблеми. Изисква се акаунт в GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Информация за отстраняване на неизправности", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { "message": "За да се избегне натоварването на доброволците с дублиращи се доклади, моля, проверете дали проблемът вече не е докладван.", "description": "A paragraph in the filter issue reporter section" @@ -167,14 +191,6 @@ "message": "Създаване на нов доклад", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Добре дошли", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Току-що инсталирахте uBO Lite. Тук можете да изберете режима на филтриране по подразбиране, който да се използва за всички уебсайтове.\n\nПо подразбиране е избран основен режим, тъй като той не изисква разрешение за четене и промяна на данни. Ако се доверите на uBO Lite, можете да му дадете широко разрешение да чете и променя данни на всички уебсайтове, за да активирате по-разширени възможности за филтриране за всички уебсайтове по подразбиране.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Режим на филтриране по подразбиране", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Навигацията към потенциално нежелани сайтове ще бъде блокирана и ще ви бъде предложена възможността да продължите.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Режим за програмисти", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Активиране на достъпа до функции, подходящи за технически потребители.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Архивиране", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Архивирайте персонализираните си настройки във файл или ги възстановете от файл.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Възстановяването ще презапише всичките ви текущи персонализирани настройки.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Намиране на списъци", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Продължаване", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Влизане в режима на временно скриване на елемента", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Излизане от режима на временно скриване на елемента", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Създаване на персонализиран филтър", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Премахване на потребителски филтър", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Преглед:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Подробности за режима на филтриране", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Потребителски правила на DNR", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Правила на DNR за ...", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Динамичен набор от правила", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Набор от правила на сесията", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Запазване", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Връщане", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Добавяне", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Импортиране и добавяне…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Експортиране…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Архивиране…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Възстановяване…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Не добавяйте съдържание от ненадеждни източници", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Брой регистрирани правила: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Преместете плъзгача, за да изберете най-подходящото съответствие", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Избор", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Преглед", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Създаване", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Изберете филтър по-долу, за да маркирате съвпадащите елементи в уеб страницата. Кликнете върху кошчето, за да премахнете филтъра.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/bn/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/bn/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/bn/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/bn/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "সেটিংস", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "সম্পর্কে", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "ফিল্টারিং মোড", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "এই ওয়েবসাইট নিয়ে সমস্যা জানাও", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "অঞ্চল, ভাষা", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "পরিবর্তনসূচি", "description": "" @@ -104,77 +124,73 @@ "description": "Shown in the About pane" }, "supportS6H": { - "message": "Report a filter issue", + "message": "ছাঁকনি নিয়ে সমস্যা জানাও", "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS3P1": { - "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", + "message": "নির্দিষ্ট ছাঁকনি বিষয়ক সমস্যা এখানে জানাও uBlockOrigin/uAssets সমস্যা ট্র্যাকার. গিটহাব অ্যাকাউন্ট প্রয়োজন।", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "সমস্যা সমাধানের তথ্য", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "একই প্রতিবেদন দুইবার এড়াতে ও স্বেচ্ছাসেবকদের বোঝা কমাতে, অনুগ্রহ করে যাচাই করো যে সমস্যাটি ইতিমধ্যে জানানো হয়নি।", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "একই রকম অভিযোগ দেখ", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { - "message": "Address of the webpage:", + "message": "ওয়েবপৃষ্ঠার ঠিকানা:", "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "The webpage…", + "message": "ওয়েবপৃষ্ঠা…", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { - "message": "-- Pick an entry --", + "message": "-- একটি ভুক্তি নির্বাচন করো --", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { - "message": "Shows ads or ad leftovers", + "message": "বিজ্ঞাপন বা বিজ্ঞাপনের অবশিষ্টাংশ দেখায়", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "Has overlays or other nuisances", + "message": "ওভারলে বা অন্যান্য উপদ্রব আছে", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { - "message": "Detects uBO Lite", + "message": "ইউবিও লাইট শনাক্ত করে", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { - "message": "Has privacy-related issues", + "message": "গোপনীয়তা-সম্পর্কিত সমস্যা আছে", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "Malfunctions when uBO Lite is enabled", + "message": "ইউবিও লাইট চালু করলে সমস্যা হয়", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { - "message": "Opens unwanted tabs or windows", + "message": "অবাঞ্ছিত ট্যাব বা জানালা খুলে", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { - "message": "Leads to badware, phishing", + "message": "ব্যাডওয়্যার, প্রতারণমূলক জায়গায় নেয়", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { - "message": "Label the webpage as “NSFW” (“Not Safe For Work”)", + "message": "ওয়েব পৃষ্ঠাটিকে “NSFW” হিসাবে চিহ্নিত করুন (“Not Safe For Work”)", "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "নতুন অভিযোগ", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "স্বাগতম", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "আপনি সবেমাত্র uBO Lite ইনস্টল করেছেন। এখানে আপনি সকল ওয়েবসাইটে ব্যবহার করার জন্য ডিফল্ট ফিল্টারিং মোড চয়ন করতে পারেন৷\n\nডিফল্টরূপে, মৌলিক মোডটি নির্বাচন করা হয়েছে কারণ এতে ডেটা পড়ার এবং পরিবর্তন করার অনুমতির প্রয়োজন হয় না৷ আপনি যদি uBO Lite-কে বিশ্বাস করেন, আপনি ডিফল্টরূপে সকল ওয়েবসাইটের জন্য আরও উন্নত ফিল্টারিং ক্ষমতা সক্ষম করার জন্য এটিকে সকল ওয়েবসাইটের ডেটা পড়তে এবং পরিবর্তন করার বিস্তৃত অনুমতি দিতে পারেন।", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "ডিফল্ট ফিল্টারিং মোড", "description": "The header text for the default filtering mode section" @@ -228,55 +244,171 @@ "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { - "message": "কতগুলো অনুরোধ ব্লক করা হয়েছে তা টুলবার আইকনে দেখাও", + "message": "কতগুলো অনুরোধ অবরুদ্ধ করা হয়েছে তা টুলবার আইকনে দেখাও", "description": "Label for a checkbox in the options page" }, "enableStrictBlockLabel": { - "message": "Enable strict blocking", + "message": "কঠোর অবরোধ চালু করো", "description": "Label for a checkbox in the options page" }, "enableStrictBlockLegend": { - "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "message": "সম্ভাব্য অযাচিত ওয়েবসাইট অবরুদ্ধ করা হবে, আর সেখানে আগানোর উপায় দেওয়া থাকবে।", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "ডেভেলপার মোড", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "প্রযুক্তিগত ব্যবহারকারীদের জন্য উপযুক্ত বৈশিষ্ট্যগুলিতে অ্যাক্সেস সক্ষম করুন", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { - "message": "Find lists", + "message": "তালিকা খুঁজো", "description": "Placeholder for the input field used to find lists" }, "strictblockTitle": { - "message": "Page blocked", + "message": "পাতা অবরুদ্ধ", "description": "Webpage title for the strict-blocked page" }, "strictblockSentence1": { - "message": "uBO Lite has prevented the following page from loading:", + "message": "ইউবিও লাইট এই পাতা লোড হওয়া আটকিয়েছে:", "description": "Sentence used in the strict-blocked page" }, "strictblockReasonSentence1": { - "message": "The page was blocked because of a matching filter in {{listname}}.", + "message": "{{listname}} এর একটি ছাঁকনির জন্য এই পাতাটি অবরুদ্ধ করা হয়েছে।", "description": "Text informing about what is causing the page to be blocked" }, "strictblockRedirectSentence1": { - "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", + "message": "এই অবরুদ্ধ পাতাটি আরেকটি ওয়েবসাইটে নেয়। এগিয়ে যেতে চাইলে, সরাসরি এই জায়গায় যাবে: {{url}}", "description": "Text warning about an incoming redirect" }, "strictblockNoParamsPrompt": { - "message": "without parameters", + "message": "প্যারামিটার নেই", "description": "Label to be used for the parameter-less URL" }, "strictblockBack": { - "message": "Go back", + "message": "ফিরে যাও", "description": "A button to go back to the previous webpage" }, "strictblockClose": { - "message": "Close this window", + "message": "জানালা বন্ধ করো", "description": "A button to close the current tab" }, "strictblockDontWarn": { - "message": "Don't warn me again about this site", + "message": "এই সাইট নিয়ে পুনরায় সতর্ক করবে না", "description": "Label for checkbox in document-blocked page" }, "strictblockProceed": { - "message": "Proceed", + "message": "এগিয়ে যাও", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "এলিমেন্ট জ্যাপার মোডে প্রবেশ করুন", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "সেভ করুন", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/br_FR/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/br_FR/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/br_FR/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/br_FR/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,18 +19,30 @@ "message": "Arventennoù", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Siloù personelaet", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Diorren", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Diwar-benn", "description": "appears as tab name in dashboard" }, "aboutPrivacyPolicy": { - "message": "Politikerezh prevezded", + "message": "Politikerezh ar vuhez prevez", "description": "Link to privacy policy on GitHub (English)" }, "popupFilteringModeLabel": { "message": "mod silañ", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "War al lec'hienn-mañ", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "Danevelliñ ur gudenn war al lec'hienn-mañ", "description": "Tooltip used for the 'chat' icon in the panel" @@ -56,11 +68,11 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupPrivacy": { - "message": "Prevezded", + "message": "Buhez prevez", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware protection, security", + "message": "Gwarez a-enep ar malware ha surentez", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -75,6 +87,14 @@ "message": "Rannvroioù, broioù", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Enporzhiañ / Ezporzhiañ", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Eilañ amañ ar siloù kenedel resis da ouzhpennañ", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Deizlevr ar cheñchamantoù", "description": "" @@ -108,11 +128,15 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS3P1": { - "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", + "message": "Danevellit kudennoù ar siloù e lec'hiennoù resis e-barzh uBlockOrigin/uAssets roll evezhiañ kudennoù. Ur c'hont GitHub zo rekis.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Titouroù diagnostikañ kudennoù", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Evit nompas sammañ ar genlabourerien a-youl vat gant meur a zanevell heñvel, gwiriit ma n'eo ket bet danevellet ho kudenn en ar-raok mar plij.", + "message": "Evit nompas sammañ ar genlabourerien a-youl vat gant meur a zanevell heñvel, gwiriit ma n'eo ket bet danevellet ho kudenn en a-raok mar plij. Notenn: ma klikit ar bouton e vo kaset anv herberc'hier ar bajenn da c'h-GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { @@ -144,7 +168,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { - "message": "Kudennoù a-fed prevezded he deus", + "message": "Kudennoù a-fed ar vuhez prevez he deus", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { @@ -156,7 +180,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { - "message": "Leads to badware, phishing", + "message": "Kas a ra da veziantoù droukyoulet pe d'an higennañ niverel", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { @@ -167,14 +191,6 @@ "message": "Sevel ur rentañ-kont nevez", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Donemat", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Emaoc'h o paouez staliañ uBO Lite. Amañ-dindan e c'hallit dibab ar mod silañ dre ziouer evit an holl lec'hiennoù.\n\nDre ziouer eo bet dibabet ar mod diazez peogwir n'eus ket ezhomm reiñ aotre da lenn ha kemmañ roadennoù da uBO Lite. M'ho peus fiziañs e uBO Lite e c'hallit reiñ aotreoù ouzhpenn dezhañ a-benn lenn ha kemmañ roadennoù en holl lec'hiennoù, mod-se e vo enaouet ar mod silañ araokaet en holl lec'hiennoù dre ziouer.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Mod silañ dre ziouer", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Stanket e vo ar merdeiñ etrezek lec'hiennoù a c'hallfe bezañ dañjerus, ha moaien a vo deoc'h dibab da genderc'hel pe get.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Mod diorroer", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Gweredekaat a ra ar fonksionelezhioù azasaet d'an implijerien deknikel.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Gwared", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Kavout rolloù", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Kenderc'hel", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Mont er mod \"dilemel elfennoù\"", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Kuitaat ar mod \"dilemel elfennoù\"", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Krouiñ ur sil personelaet", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Lemel ur sil personelaet", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Gwelet:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Munudoù ar mod silañ", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Reolennoù DNR personelaet", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Reolennoù DNR eus …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Hollad reolennoù dinamek", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Hollad reolennoù an estez", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Enrollañ", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Nullañ", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Ouzhpennañ", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Enporzhiañ hag ouzhpennañ", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Ezporzhiañ", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Gwarediñ…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Arabat ouzhpennañ danvez a zeu diouzh mammennoù douetus.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Niver a reolennoù marilhet: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Dibunit ar reti evit diuzañ ar pezh a glot ar muiañ", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Diuzañ", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Rakwel", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Krouiñ", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Diuzit ur sil amañ-dindan evit sklêrijennañ an elfennoù kendere er bajenn web. Klikit ar pod-lastez evit lemel ur sil.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/bs/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/bs/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/bs/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/bs/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Postavke", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Razvoj", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "O aplikaciji", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "način filtriranja", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Na ovoj web stranici", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Prijavi problem", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Regije, jezici", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Dnevnik izmjena", "description": "" @@ -104,77 +124,73 @@ "description": "Shown in the About pane" }, "supportS6H": { - "message": "Report a filter issue", + "message": "Prijavi problem s filterom", "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS3P1": { - "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", + "message": "Prijavite probleme s filterima na određenim web stranicama uBlockOrigin/uAssets sistemu za praćenje problema . Potreban je GitHub račun.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Informacije o rješavanju problema", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "Kako biste izbjegli opterećivanje volontera duplim prijavama, molimo vas da provjerite da problem već nije prijavljen. Napomena: klikom na dugme, porijeklo stranice će biti poslano GitHubu.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Pronađite slične izvještaje na GitHubu", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { - "message": "Address of the webpage:", + "message": "Adresa web stranice:", "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "The webpage…", + "message": "Web stranica…", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { - "message": "-- Pick an entry --", + "message": "-- Odaberite unos --", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { - "message": "Shows ads or ad leftovers", + "message": "Prikazuje oglase ili ostatke oglasa", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "Has overlays or other nuisances", + "message": "Ima prekrivajuće slojeve ili druge smetnje", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { - "message": "Detects uBO Lite", + "message": "Detektira uBO Lite", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { - "message": "Has privacy-related issues", + "message": "Ima problema s privatnošću", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "Malfunctions when uBO Lite is enabled", + "message": "Kvarovi kada je uBO Lite omogućen", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { - "message": "Opens unwanted tabs or windows", + "message": "Otvara neželjene kartice ili prozore", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { - "message": "Leads to badware, phishing", + "message": "Vodi do zlonamjernog softvera i phishinga", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { - "message": "Label the webpage as “NSFW” (“Not Safe For Work”)", + "message": "Označite web stranicu kao \"NSFW\" ( \"Nije sigurno za rad\" )", "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Kreiraj novi izvještaj na GitHubu", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Dobrodošli", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Upravo ste instalirali uBO Lite. Ovdje možete odabrati zadani način filtriranja koji će se koristiti na svim web stranicama.\n\nPrema zadanim postavkama, Osnovni način rada je odabran jer ne zahtijeva dozvolu za čitanje i izmjenu podataka. Ako vjerujete uBO Lite-u, možete mu dati široku dozvolu za čitanje i izmjenu podataka na svim web lokacijama kako bi se omogućile naprednije mogućnosti filtriranja za sve web stranice prema zadanim postavkama.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Zadani način filtriranja", "description": "The header text for the default filtering mode section" @@ -200,7 +216,7 @@ "description": "Name of blocking mode 3" }, "basicFilteringModeDescription": { - "message": " Osnovno mrežno filtriranje sa odabranih lista filtera.\n\nNe zahtijeva dozvolu za čitanje i modificiranje podataka na web stranicama.", + "message": "Osnovno filtriranje mreže iz odabranih lista filtera.\n\nNe zahtijeva dozvolu za čitanje i izmjenu podataka na web stranicama.", "description": "This describes the 'basic' filtering mode" }, "optimalFilteringModeDescription": { @@ -212,11 +228,11 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Lista imena hostova za koja se neće vršiti filtriranje", + "message": "Lista web stranica za koje se neće vršiti filtriranje.", "description": "A short description for the editable field which lists trusted sites" }, "noFilteringModePlaceholder": { - "message": "[hostnames only]\nexample.com\ngames.example\n...", + "message": "[samo imena hostova]\nexample.com\ngames.example\n...", "description": "Default text for in edit field" }, "behaviorSectionLabel": { @@ -232,51 +248,167 @@ "description": "Label for a checkbox in the options page" }, "enableStrictBlockLabel": { - "message": "Enable strict blocking", + "message": "Omogući strogo blokiranje", "description": "Label for a checkbox in the options page" }, "enableStrictBlockLegend": { - "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "message": "Navigacija do potencijalno neželjenih stranica bit će blokirana i bit će vam ponuđena mogućnost da nastavite.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Režim za razvojne programere", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Omogućava pristup funkcijama pogodnim za tehničke korisnike.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { - "message": "Find lists", + "message": "Pronađi liste", "description": "Placeholder for the input field used to find lists" }, "strictblockTitle": { - "message": "Page blocked", + "message": "Stranica je blokirana", "description": "Webpage title for the strict-blocked page" }, "strictblockSentence1": { - "message": "uBO Lite has prevented the following page from loading:", + "message": "uBO Lite je spriječio učitavanje sljedeće stranice:", "description": "Sentence used in the strict-blocked page" }, "strictblockReasonSentence1": { - "message": "The page was blocked because of a matching filter in {{listname}}.", + "message": "Stranica je blokirana zbog odgovarajućeg filtera u {{listname}}.", "description": "Text informing about what is causing the page to be blocked" }, "strictblockRedirectSentence1": { - "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", + "message": "Blokirana stranica želi preusmjeriti na drugu stranicu. Ako odlučite nastaviti, bit ćete direktno na: {{url}}", "description": "Text warning about an incoming redirect" }, "strictblockNoParamsPrompt": { - "message": "without parameters", + "message": "bez parametara", "description": "Label to be used for the parameter-less URL" }, "strictblockBack": { - "message": "Go back", + "message": "Nazad", "description": "A button to go back to the previous webpage" }, "strictblockClose": { - "message": "Close this window", + "message": "Zatvori ovaj prozor", "description": "A button to close the current tab" }, "strictblockDontWarn": { - "message": "Don't warn me again about this site", + "message": "Ne upozoravaj me više o ovoj stranici", "description": "Label for checkbox in document-blocked page" }, "strictblockProceed": { - "message": "Proceed", + "message": "Nastavite", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Ukloni element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Izlaz iz načina rada za zatvaranje elemenata", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Kreirajte prilagođeni filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Uklonite prilagođeni filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Prikaz:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Detalji načina filtriranja", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Prilagođena pravila DNR-a", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR pravila …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dinamički skup pravila", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Skup pravila sesije", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Sačuvaj", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Vrati", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Uvezi i dodaj…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Izvoz…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Ne dodavajte sadržaj iz nepouzdanih izvora", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Broj registrovanih pravila: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Pomaknite klizač da biste odabrali najbolje podudaranje", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Odaberite", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Pregled", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Napravi", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Odaberite filter ispod da biste istaknuli odgovarajuće elemente na web stranici. Kliknite na kantu za smeće da biste uklonili filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ca/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ca/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ca/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ca/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Configuració", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Filtres personalitzats", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Desenvolupament", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Quant a", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "mode de filtre", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "En aquest lloc web", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "Informa d'un problema en aquest lloc web", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "Regions, llengües", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Importa/Exporta", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Enganxeu aquí els filtres cosmètics que voleu afegir", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Registre de canvis", "description": "" @@ -111,8 +131,12 @@ "message": "Informeu d'un problema en llocs web específics mitjançant el uBlockOrigin/uAssets seguiment d'errors. Cal un compte al GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Informació de resolució de problemes", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Per evitar carregar els voluntaris amb informes duplicats, verifiqueu que el problema encara no s'hagi notificat.", + "message": "Per a evitar la sobrecàrrega del nostre voluntariat amb informes duplicats, verifiqueu abans que el problema encara no s'ha notificat. Nota: En fer clic, enviareu la pàgina causant al nostre GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { @@ -167,14 +191,6 @@ "message": "Crea un informe nou", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Us donem la benvinguda", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Acabeu d'instal·lar l'uBO Lite. Aquí podeu triar el mode de filtrat per defecte per utilitzar-lo a tots els llocs web.\n\nPer defecte, el mode Bàsic està seleccionat perquè no requereix permís per llegir i canviar dades. Si confieu en l'uBO Lite, podeu donar-li un ampli permís per llegir i canviar dades a tots els llocs web per tal d'activar capacitats de filtratge més avançades per a tots els llocs web per defecete.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Mode de filtratge per defecte", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Es blocarà la navegació en webs potencialment no desitjables, oferint-vos la possibilitat de continuar.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Mode de desenvolupador", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Habilita l'accés a funcions adequades per a usuaris tècnics.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Còpia de seguretat / Restaura", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Feu una còpia de seguretat de la vostra configuració personalitzada a un fitxer o restaureu la vostra configuració personalitzada des d'un fitxer.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "La restauració sobreescriurà tots els paràmetres personalitzats actuals.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Cerca llistes", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Continua", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Accedeix al mode d'eliminació d'elements", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Surt del mode d'eliminació d'elements", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Crea un filtre personalitzat", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Elimina un filtre personalitzat", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Vista:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Detalls del mode de filtratge", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Regles DNR personalitzades", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Regles DNR de…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Conjunt de regles dinàmiques", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Conjunt de regles de sessió", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Desa", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Restaura", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Afegeix", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Importa i annexa…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exporta…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Còpia de seguretat…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restaura…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "No afegiu contingut de fonts no fiables", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Nombre de regles registrades: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Moveu el control lliscant per a seleccionar la millor coincidència", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Selecciona", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Previsualitza", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Crea", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Seleccioneu un filtre a continuació per a ressaltar els elements coincidents de la pàgina web. Feu clic a la paperera per a eliminar un filtre.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/cs/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/cs/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/cs/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/cs/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Blokátor obsahu vyžadující méně oprávnění. Blokuje reklamy, sledovače, těžaře a jiné ihned po instalaci.", + "message": "Účinný blokátor obsahu. Okamžitě po instalaci blokuje reklamy, sledovače, těžaře a další.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Nastavení", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Vlastní filtry", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Vývoj", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "O rozšíření", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "Filtrovací režim", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Na této webové stránce", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "Nahlásit problém na této webové stránce", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "Regionální, jazykové", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Vložte sem konkrétní kosmetické filtry, které chcete přidat", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Přehled změn", "description": "" @@ -111,6 +131,10 @@ "message": "Nahlaste problémy s filtrem u učitých webových stránek do sledovače problémů uBlockOrigin/uAssets. Vyžaduje účet GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Informace o řešení problémů", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { "message": "Abyste dobrovolníky nezatěžovali duplicitními hlášeními, ověřte si, zda již problém nebyl nahlášen.", "description": "A paragraph in the filter issue reporter section" @@ -167,14 +191,6 @@ "message": "Vytvořit nové hlášení", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Vítejte", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Právě jste nainstalovali uBO Lite. Zde si můžete vybrat výchozí režim filtrování pro použití na všech webových stránkách.\n\nVe výchozím nastavení je vybrán režim Základní, protože nevyžaduje oprávnění ke čtení a změně dat. Pokud důvěřujete uBO Lite, můžete mu udělit široké oprávnění číst a měnit data na všech webových stránkách, abyste ve výchozím nastavení povolili pokročilejší možnosti filtrování pro všechny webové stránky.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Výchozí filtrovací režim", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigace na potenciálně nežádoucí stránky bude zablokována a bude vám nabídnuta možnost pokračovat.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Vývojářský režim", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Umožňuje přístup k funkcím vhodným pro technicky zdatné uživatele.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Záloha", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Zálohování vlastních nastavení do souboru nebo obnovení vlastních nastavení ze souboru.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Obnovení přepíše všechna vaše aktuální vlastní nastavení.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Najít seznamy", "description": "Placeholder for the input field used to find lists" @@ -268,7 +304,7 @@ "description": "A button to go back to the previous webpage" }, "strictblockClose": { - "message": "Zavřít toto okno", + "message": "Zavřít okno", "description": "A button to close the current tab" }, "strictblockDontWarn": { @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Pokračovat", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Přejít do režimu dočasného skrytí prvků", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Opustit režim dočasného skrytí prvků", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Vytvořit vlastní filtr", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Odebrat vlastní filtr", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Zobrazit:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Detaily filtovacího módu", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Vlastní pravidla DNR", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR pravidla …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamický seznam pravidel", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Uložit", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Vrátit", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Přidat", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Importovat a připojit…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exportovat…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Zálohovat…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Obnovit…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Nepřidávat filtry z nedůvěryhodných zdrojů", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Počet registrovaných pravidel: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Posunutím jezdce vyberte nejlepší shodu", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Vybrat", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Náhled", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Vytvořit", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Výběrem níže uvedeného filtru zvýrazníte odpovídající prvky na webové stránce. Kliknutím na koš filtr odstraníte.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/cv/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/cv/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/cv/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/cv/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "A permission-less content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", + "message": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Report an issue", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Regions, languages", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Changelog", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/cy/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/cy/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/cy/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/cy/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Gosodiadau", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Datblygu", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Ynghylch", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "modd hidlo", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Ar y wefan hon", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "Rhoi gwybod am broblem ar y wefan hon", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "Rhanbarthau, ieithoedd", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Cofnod newidiadau", "description": "" @@ -111,20 +131,24 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Dod o hyd i adroddiadau tebyg ar GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { - "message": "Address of the webpage:", + "message": "Cyfeiriad y dudalen we:", "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "The webpage…", + "message": "Y dudalen we…", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Croeso", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Modd datblygwr", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -264,19 +300,115 @@ "description": "Label to be used for the parameter-less URL" }, "strictblockBack": { - "message": "Go back", + "message": "Yn ôl", "description": "A button to go back to the previous webpage" }, "strictblockClose": { - "message": "Close this window", + "message": "Cau'r ffenestr hon", "description": "A button to close the current tab" }, "strictblockDontWarn": { - "message": "Don't warn me again about this site", + "message": "Peidio â'm rhybuddio eto am y wefan hon", "description": "Label for checkbox in document-blocked page" }, "strictblockProceed": { - "message": "Proceed", + "message": "Parhau", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Galluogi'r modd saethu elfen", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Gadael y modd saethu elfen", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Cadw", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Dychwelwch", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Ychwanegwch", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Allforio", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/da/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/da/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/da/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/da/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "En tilladelsesløs indholdsblocker. Blokerer som standard annoncer, trackere, minere mv. straks efter installationen.", + "message": "En effektiv indholdsblocker. Blokerer annoncer, trackere, minere mm. umiddelbart efter installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Indstillinger", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Tilpassede filtre", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Udvikl", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Om", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtreringstilstand", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "På dette websted", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Anmeld et problem på dette websted", + "message": "Anmeld et problem", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -60,7 +72,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware-domæner", + "message": "Malware-beskyttelse, sikkerhed", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -75,6 +87,14 @@ "message": "Regioner, sprog", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import/ Eksport", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Indsæt bestemte kosmetiske filtre hér for at tilføje", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Ændringslog", "description": "" @@ -111,12 +131,16 @@ "message": "Anmeld filterproblemer med bestemte websteder til uBlockOrigin/uAssets-problemsporingen. Kræver en GitHub-konto.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Fejlfindingsinformation", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "For at undgå at belaste frivillige med dubletanmeldelser, så tjek venligst, at problemet ikke allerede er anmeldt.", + "message": "For at undgå at bebyrde frivillige med dubletanmeldelser, så tjek venligst, at problematikken ikke allerede er anmeldt. Bemærk: Ved at klikke på knappen, sendes sidens oprindelse til GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find lign. anmeldelser", + "message": "Find lign. anmeldelser på GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Opret ny anmeldelse", + "message": "Opret ny anmeldelse på GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Velkommen", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Du har netop installeret uBO Lite. Her kan den standardfiltreringstilstand vælges, der skal bruges på alle websteder.\n\nStandardvalget er Basis-tilstand, da den ikke kræver tilladelse til at læse og ændre data. Er uBO Lite betroet, kan den udvidede tilladelse til at læse og ændre data på alle websteder tildeles for som standard at aktivere mere avancerede filtreringsfunktioner for alle websteder.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Standardfiltreringstilstand", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigering til potentielt uønskede websteder blokeres, men man tilbydes muligheden for at fortsætte.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Udviklertilstand", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Aktiverer adgang til funktioner egnede for tekniske brugere.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Sikkerhedskopiér", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Sikkerhedskopiér tilpassede indstillinger til en fil, eller gendan tilpassede indstillinger fra en fil.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Gendannelse overskriver alle nuværende tilpassede indstillinger.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lister", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Fortsæt", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Fjern et element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Forlad elementdræber­tilstand", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Opret et tilpasset filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Fjern et tilpasset filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Vis:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtreringstilstandsdetaljer", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Tilpassede DNR-regler", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR-regler for…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamiske regelsæt", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Sessionsregelsæt", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Gem", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Tilbagefør", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Tilføj", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Importér og tilføj…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Eksportér…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Sikkerhedskopiér…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Gendan…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Tilføj ikke indhold fra ikke-betroede kilder.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Antal registrerede regler : {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Flyt skyderen for at vælge det bedste match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Vælg", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Forhåndsvisning", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Opret", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Vælg et filter nedenfor for at fremhæve matchende elementer på websiden. Klik på papirkurven for at fjerne et filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/de/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/de/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/de/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/de/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Ein Inhaltsblocker, der ohne Berechtigungen auskommt. Blockiert Werbung, Tracker und mehr sofort nach der Installation.", + "message": "Ein effizienter Inhaltsblocker. Blockiert Werbung, Tracker und mehr sofort nach der Installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Einstellungen", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Eigene Filter", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Entwickeln", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Über", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "Filtermodus", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Auf dieser Website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Ein Problem mit dieser Website melden", + "message": "Ein Problem melden", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Regionen, Sprachen", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Importieren und exportieren", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Kosmetische Filter zum Hinzufügen einfügen", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Änderungsprotokoll", "description": "" @@ -111,12 +131,16 @@ "message": "Bitte melden Sie Filterprobleme mit bestimmten Websites an den uBlockOrigin/uAssets Issue Tracker. Erfordert ein GitHub-Konto.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Informationen zur Fehlerbehebung", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Um die Freiwilligen nicht mit doppelten Meldungen zu belasten, vergewissern Sie sich bitte, dass das Problem nicht schon einmal gemeldet wurde.", + "message": "Um die Freiwilligen nicht mit doppelten Meldungen zu überlasten, vergewissern Sie sich bitte, dass das Problem noch nicht gemeldet wurde. Hinweis: Das Anklicken der Schaltfläche übermittelt den Ursprung der Seite an GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Ähnliche Meldungen finden", + "message": "Ähnliche Meldungen auf GitHub finden", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Neue Meldung erstellen", + "message": "Neue Meldung auf GitHub erstellen", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Willkommen", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Sie haben soeben uBO Lite installiert. Sie können hier den Standardfiltermodus auswählen, der auf allen Websites angewendet werden soll.\n\nStandardmäßig ist der einfache Modus ausgewählt, weil er keine Berechtigung zum Lesen und Ändern von Daten erfordert. Wenn Sie uBO Lite vertrauen, können Sie dieser Erweiterung eine weitreichende Berechtigung zum Lesen und Ändern von Daten auf allen Websites erteilen, um standardmäßig erweiterte Filterfunktionen für alle Websites zu aktivieren.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Standardfiltermodus", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Die Navigation zu potenziell unerwünschten Websites wird verhindert, jedoch wird eine Möglichkeit zum Fortfahren angeboten.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Entwicklermodus", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Ermöglicht den Zugriff auf Funktionen, die für technisch Versierte bestimmt sind.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Sicherung", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Alle angepassten Einstellungen können in eine Datei gesichert oder aus einer Datei wiederhergestellt werden.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Durch das Wiederherstellen werden alle angepassten Einstellungen überschrieben.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Listen suchen", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Fortfahren", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Ein Element entfernen", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Temporären Modus beenden", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Eigenen Filter erstellen", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Eigenen Filter entfernen", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Ansicht:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Details zum Filtermodus", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Eigene DNR-Regeln", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR-Regeln von …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamische Regeln", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Regeln der aktuellen Sitzung", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Speichern", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Rückgängig machen", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Hinzufügen", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Importieren und ergänzen …", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exportieren …", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Sichern …", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Wiederherstellen …", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Verwenden Sie keine Regeln aus unseriösen Quellen", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Anzahl erfasster Regeln: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Schieberegler bewegen, um die beste Übereinstimmung auszuwählen", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Auswählen", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Vorschau", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Erstellen", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Das Auswählen eines unten stehenden Filters hebt übereinstimmende Elemente auf der Webseite hervor. Auf den Mülleimer klicken, um einen Filter zu entfernen.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/el/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/el/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/el/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/el/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Ρυθμίσεις", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Προσαρμοσμένα φίλτρα", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Ανάπτυξη", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Σχετικά", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "λειτουργία φιλτραρίσματος", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Για αυτόν τον ιστότοπο", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "Αναφορά ενός ζητήματος σε αυτόν τον ιστότοπο", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "Περιοχές, γλώσσες", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Εισαγωγή / Εξαγωγή", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Επικολλήστε εδώ για προσθέσετε φίλτρα για συγκεκριμένα διακοσμητικά", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Αρχείο αλλαγών", "description": "" @@ -104,23 +124,27 @@ "description": "Shown in the About pane" }, "supportS6H": { - "message": "Αναφορά ζητήματος φίλτρου", + "message": "Αναφορά προβλήματος φίλτρου", "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS3P1": { - "message": "Αναφέρετε ζητήματα φίλτρου για συγκεκριμένους ιστοτόπους στο εργαλείο παρακολούθησης ζητημάτων του uBlockOrigin/uAssets. Απαιτείται λογαριασμός GitHub.", + "message": "Αναφέρετε προβλήμα φίλτρου για συγκεκριμένους ιστοτόπους στο εργαλείο παρακολούθησης ζητημάτων του uBlockOrigin/uAssets. Απαιτείται λογαριασμός GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Πληροφορίες για αντιμετώπιση προβλημάτων", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Για να αποφύγετε την επιβάρυνση των εθελοντών με διπλές αναφορές, βεβαιωθείτε ότι το ζήτημα δεν έχει ήδη αναφερθεί.", + "message": "Για να μην επιβαρυνθούν οι εθελοντών με διπλές αναφορές, βεβαιωθείτε ότι το ζήτημα δεν έχει ήδη αναφερθεί.Σημείωση: Με το πάτημα του κουμπιού, θα σταλεί η σελίδα προέλευσης στο GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Βρείτε παρόμοιες αναφορές", + "message": "Βρείτε παρόμοιες αναφορές στο GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { - "message": "Διεύθυνση ιστοσελίδας:", + "message": "Διεύθυνση της ιστοσελίδας:", "description": "Label for the URL of the page" }, "supportS6Select1": { @@ -167,14 +191,6 @@ "message": "Δημιουργία νέας αναφοράς", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Καλώς ορίσατε", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Μόλις εγκαταστήσατε το uBO Lite. Μπορείτε να επιλέξετε εδώ την προεπιλεγμένη λειτουργία φιλτραρίσματος για χρήση σε όλους τους ιστότοπους.\n\nΑπό προεπιλογή, έχει επιλεγεί η λειτουργία Βασική επειδή δεν απαιτεί άδεια ανάγνωσης και αλλαγής δεδομένων. Εάν εμπιστεύεστε το uBO Lite, μπορείτε να του δώσετε ευρεία άδεια να διαβάζει και να αλλάζει δεδομένα σε όλους τους ιστότοπους, προκειμένου να ενεργοποιηθούν πιο προηγμένες δυνατότητες φιλτραρίσματος για όλους τους ιστότοπους από προεπιλογή.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Προεπιλεγμένη λειτουργία φιλτραρίσματος", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Θα απετραπεί η πρόσβαση σε πιθανά ανεπιθύμητους ιστοτόπους. Θα σας προσφερθεί η επιλογή να συνεχίσετε.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Λειτουργία προγραμματιστή", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Ενεργοποίηση πρόσβασης σε δυνατότητες κατάλληλες για τεχνικούς χρήστες.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Αντίγραφα ασφαλείας", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Δημιουργήστε ένα αντίγραφο ασφαλείας των προσαρμοσμένων ρυθμίσεών σας ή επαναφέρετε τις προσαρμοσμένες ρυθμίσεις από ένα αρχείο αντιγράφου ασφαλείας.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Η επαναφορά θα έχει ως αποτέλεσμα την αντικατάσταση των τρεχόντων προσαρμοσμένων ρυθμίσεών σας.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Εύρεση λιστών", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Συνέχεια", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Είσοδος σε λειτουργία αφαίρεσης στοιχείων", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Έξοδος από λειτουργία αφαίρεσης στοιχείων", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Δημιουργία προσαρμοσμένου φίλτρου", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Αφαίρεση προσαρμοσμένου φίλτρου", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Προβολή:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Λεπτομέρειες λειτουργίας φιλτραρίσματος", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Προσαρμοσμένοι κανόνες DNR", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Κανόνες DNR του …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Σετ κανόνων που είναι δυναμικοί", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Σετ κανόνων για τη συνέδρεια", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Αποθήκευση", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Επαναφορά", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Προσθήκη", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Εισαγωγή και προσθήκη…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Εξαγωγή…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Δημιουργία αντιγράφου ασφαλείας…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Επαναφορά ρυθμίσεων…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Να μην προστίθενται περιεχόμενο από μη αξιόπιστες πηγές.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Σύνολο εγγεγραμμένων κανόνων: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Μετακινήστε το ρυθμιστικό για να επιλέξετε την καλύτερη αντιστοίχιση", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Επιλογή", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Προεπισκόπηση", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Δημιουργία", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Επιλέξτε ένα φίλτρο παρακάτω για να επισημάνετε τα στοιχεία που αντιστοιχούν στην ιστοσελίδα. Κάντε κλικ στον κάδο απορριμμάτων για να αφαιρέσετε ένα φίλτρο.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/en/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/en/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/en/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/en/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "A permission-less content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", + "message": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Report an issue", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Regions, languages", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Changelog", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/en_GB/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/en_GB/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/en_GB/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/en_GB/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "An experimental, permission-less content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", + "message": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "Report an issue on this website", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "Regions, languages", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Change-log", "description": "" @@ -111,8 +131,12 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { @@ -167,14 +191,6 @@ "message": "Create new report", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enable access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Backup your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Enter element zapper mode", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Backup…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the dustbin to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/eo/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/eo/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/eo/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/eo/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "A permission-less content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", + "message": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Agordoj", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Pri", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Report an issue", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Regions, languages", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Ŝanĝprotokolo", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Bonvenon", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/es/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/es/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/es/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/es/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Un bloqueador de contenido con menos permisos. Bloquea anuncios, rastreadores, criptomineros y aún más.", + "message": "Un bloqueador de contenido eficiente. Bloquea anuncios, rastreadores, criptomineros y aún más.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Configuración", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Filtros personalizados", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Desarrollo", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Acerca de", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "modo de filtrado", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "En este sitio web", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Reportar un problema en este sitio web", + "message": "Reportar un problema", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Regiones, idiomas", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Importar / Exportar", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Pega aquí los filtros cosméticos específicos a añadir", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Registro de cambios", "description": "" @@ -111,12 +131,16 @@ "message": "Reportar problemas de filtros con sitios web específicos en el registro de problemas uBlockOrigin/uAssets. Requiere una cuenta en GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Información para solucionar problemas", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Para evitar sobrecargar a voluntarios con reportes duplicados, verifica que el problema no haya sido reportado.", + "message": "Para evitar sobrecargar a voluntarios con reportes duplicados, verifica que el problema no haya sido reportado. Nota: al hacer clic en el botón, hará que el origen de la página se envíe a GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Encontrar reportes similares", + "message": "Encontrar reportes similares en GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Crear nuevo reporte", + "message": "Crear nuevo reporte en GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Bienvenida", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Acabas de instalar uBO Lite. Aquí puedes elegir el modo de filtrado predeterminado que se utilizará en todos los sitios web.\n\nPor defecto, el modo básico está seleccionado porque no requiere permiso para leer y modificar datos. Si confías en uBO Lite, puedes otorgarle un permiso amplio para leer y modificar datos en todos los sitios web para habilitar capacidades de filtrado más avanzadas para todos los sitios web de forma predeterminada.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Modo de filtrado predeterminado", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "La navegación a sitios potencialmente no deseados será bloqueada, y se te ofrecerá la opción de continuar.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Modo desarrollador", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Habilita acceso a características aptas para usuarios técnicos.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Respaldar", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Haz un respaldo de tu configuración personalizada en un archivo o restaura tu configuración personalizada desde uno.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "La restauración sobrescribirá toda tu configuración personalizada actual.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Encontrar listas", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Continuar", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Eliminar un elemento", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Salir del modo eliminación de elementos", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Crear un filtro personalizado", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Eliminar un filtro personalizado", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Ver:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Detalles del modo de filtrado", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Reglas DNR personalizadas", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Reglas DNR de …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Conjunto de reglas dinámicas", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Conjunto de reglas de sesión", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Guardar", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revertir", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Añadir", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Importar y anexar…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exportar…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Respaldar…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restaurar…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "No añadas contenido de fuentes no confiables", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Número de reglas registradas: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Mueve el control deslizante para seleccionar la mejor coincidencia", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Elegir", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Vista previa", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Crear", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Selecciona un filtro abajo para resaltar los elementos coincidentes en la página web. Haz clic en la papelera para eliminar un filtro.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/et/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/et/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/et/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/et/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Sätted", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Isetehtud filtrid", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Arendajale", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Teave", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtreerimisrežiim", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Sellel veebilehel", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Teavita veast selle veebilehega", + "message": "Teavita veast", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Regioonid, keeled", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Impordi/ekspordi", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Kindlate kosmeetiliste filtrite lisamiseks asetage need siia", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Muudatuste logi", "description": "" @@ -111,12 +131,16 @@ "message": "Teavita vigasest filtrist kindlate veebilehtedega uBlockOrigin/uAssets vigade andmebaasi kaudu. Nõuab GitHubi kontot.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Tõrkeotsingu teave", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Vabatahtlike koormamise vältimiseks samade teadetega veenduge, et keegi pole selle murega juba varem pöördunud.", + "message": "Vabatahtlike koormamise vältimiseks samade teadetega veenduge, et keegi pole selle murega juba varem pöördunud. Märge! Nupule klõpsamisega saadetakse GitHubile lehekülje aadress.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Leidke sarnased aruanded", + "message": "Leia GitHubist sarnaseid aruandeid", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Loo uus aruanne", + "message": "Loo GitHubis uus aruanne", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Tere tulemast", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Olete paigaldanud uBO Lite'i. Nüüd valige kõigil veebilehtedel kasutatav üldine filtreerimisrežiim.\n\nTavaliselt kehtib Põhiline režiim, kuna see ei vaja andmete lugemise ja muutmise luba. uBO Lite'i usaldamisel saate sel lubada andmeid lugeda ja muuta kõigil veebilehtedel, et neid saaks vaikimisi filtreerida põhjalikumalt.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Tavaline filtreerimisrežiim", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Kahtlastele veebilehtedele suunamist takistatakse ja pakutakse võimalust jätkamiseks.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Arendaja režiim", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Luba juurdepääs tehnilise taibuga kasutajatele mõeldud võimalustele.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Varundamine / taastamine", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Varunda eriseadistused faili või taasta need failist.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Taastamine asendab olemasolevad seadistused.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Otsi nimekirju", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Jätka", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Eemalda element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Välju elemendi hävitusrežiimist", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Loo ise filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Eemalda enda filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Vaade:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtreerimisrežiimi andmed", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Enda aadressiresolverite avastamise reeglid", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Aadressiresolverite avastamise reeglid sellelt …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dünaamiline reeglitekogumik", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Seansi reeglitekogumik", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Salvesta", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Taasta", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Lisa", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Impordi ja lisa…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Ekspordi…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Varunda…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Taasta…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Lisa sisu vaid usaldusväärsetest allikatest", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Registreeritud reeglite arv: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Parima tulemuse saavutamiseks liigutage liugurit", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Vali", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Eelvaade", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Loo", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Valige allolev filter, et tõsta esile veebilehel kattuvad elemendid. Filtri eemaldamiseks klõpsake prügikasti.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/eu/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/eu/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/eu/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/eu/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Ezarpenak", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Honi buruz", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "Iragazteko modua", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Webgune honetan arazo baten berri eman", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Eskualdeak, hizkuntzak", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Aldaketen erregistroa", "description": "" @@ -104,19 +124,23 @@ "description": "Shown in the About pane" }, "supportS6H": { - "message": "Report a filter issue", + "message": "iragazkiko arazo baten berria eman", "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS3P1": { "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -140,7 +164,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { - "message": "Detects uBO Lite", + "message": "uBO Lite detektatzen da", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Ongi etorri", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "uBO Lite instalatu berri duzu. Hemen, webgune guztietan erabiltzeko iragazteko modu lehenetsia hauta dezakezu.\n\nAurrez zehaztuta, Oinarrizkoa modua hautatzen da, ez baita baimenik behar datuak irakurtzeko eta aldatzeko. uBO Lite-n konfiantza baduzu, webgune guztietan datuak irakurtzeko eta aldatzeko baimen zabala eman dezakezu, webgune guztietarako iragazteko gaitasun aurreratuagoak gaitzeko, aldez aurretik zehaztuta.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Lehenetsitako iragazteko modua", "description": "The header text for the default filtering mode section" @@ -237,14 +253,34 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" }, "strictblockTitle": { - "message": "Page blocked", + "message": "Blokeatutako orrialdea", "description": "Webpage title for the strict-blocked page" }, "strictblockSentence1": { @@ -260,23 +296,119 @@ "description": "Text warning about an incoming redirect" }, "strictblockNoParamsPrompt": { - "message": "without parameters", + "message": "parametrorik gabe", "description": "Label to be used for the parameter-less URL" }, "strictblockBack": { - "message": "Go back", + "message": "Joan atzera", "description": "A button to go back to the previous webpage" }, "strictblockClose": { - "message": "Close this window", + "message": "Itxi leiho hau", "description": "A button to close the current tab" }, "strictblockDontWarn": { - "message": "Don't warn me again about this site", + "message": "Ez esan ezer berriz ere orrialde honi buruz", "description": "Label for checkbox in document-blocked page" }, "strictblockProceed": { - "message": "Proceed", + "message": "Aurrera", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Sartu elementua zapper moduan", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Irten elementua zapper moduan", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/fa/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/fa/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/fa/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/fa/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "تنظیمات", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "درباره", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Report an issue", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "مناطق، زبانها", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "گزارش دگرگونی", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "درود", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/fi/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/fi/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/fi/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/fi/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Käyttöoikeudeton estotyökalu, joka estää välittömästi asennuksesta lähtien mm. mainokset, seurannat ja kryptolouhijat.", + "message": "Tehokas estotyökalu, joka estää heti asennuksen jälkeen mm. mainokset, seurannat ja kryptolouhijat.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Asetukset", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Omat suodattimet", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Kehitys", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Tietoja", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "suodatustila", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Tällä sivustolla", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Ilmoita ongelmasta tällä verkkosivustolla", + "message": "Ilmoita ongelmasta", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -60,7 +72,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Haittaohjelmia jakelevat verkkotunnukset", + "message": "Haittaohjelmasuojaus, tietoturva", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -75,6 +87,14 @@ "message": "Alueet, kielet", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Tuonti / Vienti", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Liitä lisättävät kosmeettiset suodattimet tähän", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Muutoshistoria", "description": "" @@ -111,12 +131,16 @@ "message": "Ilmoita sivustokohtaisista suodatinongelmista uBlockOrigin/uAssets -ongelmaseurantaan. Vaatii GitHub-tilin.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Vianselvitystiedot", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Välttääksesi vapaaehtoisten kuormittamisen ylimääräisillä ilmoituksilla, tarkista ensin onko ongelmasta jo ilmoitettu.", + "message": "Välttääksesi vapaaehtoisten kuormittamisen ylimääräisillä ilmoituksilla, tarkasta ensin onko ongelmasta jo ilmoitettu. Huomioi: Painikkeen painallus lähettää sivun osoitteen GitHubiin.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Etsi samankaltaisia ilmoituksia", + "message": "Etsi GitHubista vastaavia ilmoituksia", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Luo uusi ilmoitus", + "message": "Luo GitHubiin uusi ilmoitus", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Tervetuloa", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Olet juuri asentanut uBO Liten. Tästä voit valita kaikilla sivustoilla oletusarvoisesti käytettävän suodatustilan.\n\nOletusarvoinen valinta on Perus-tila, koska se ei vaadi tietojen luku- ja muokkausoikeutta. Jos luotat uBO Liteen, voit myöntää sille kaikki sivustot kattavan laajan tietojen luku- ja muokkausoikeuden, jolloin edistyneemmät suodatusominaisuudet ovat oletusarvoisesti käytössä kaikilla sivustoilla.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Oletusarvoinen suodatustila", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Potentiaalisesti ei-toivottujen sivustojen avaaminen estetään mahdollisuudella jatkaa.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Kehittäjätila", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Aktivoi teknisille käyttäjille suunnatut ominaisuudet.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Varmuuskopioi / Palauta", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Varmuuskopioi asetuksesi tiedostoon, tai palauta aiempi varmuuskopio.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Palautus korvaa kaikki nykyiset asetuksesi.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Etsi listoja", "description": "Placeholder for the input field used to find lists" @@ -260,7 +296,7 @@ "description": "Text warning about an incoming redirect" }, "strictblockNoParamsPrompt": { - "message": "ilman parametreja", + "message": "parametritön", "description": "Label to be used for the parameter-less URL" }, "strictblockBack": { @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Jatka", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Poista elementti", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Poistu elementtien piilotustilasta", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Luo uusi suodatin", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Poista oma suodatin", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Näytä:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Suodatustilan tiedot", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Omat DNR-säännöt", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR-säännöt lähteestä…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynaaminen sääntöryhmä", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Istunnon sääntöryhmä", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Tallenna", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Palauta", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Lisää", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Tuo ja lisää…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Vie…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Varmuuskopioi…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Palauta…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Älä lisää sisältöä lähteistä, joihin et luota.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Rekisteröityjen sääntöjen määrä: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Valitse sopivin vaihtoehto siirtämällä säädintä", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Valitse", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Esikatsele", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Luo", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Valitse alta suodatin korostaaksesi verkkosivulta sitä vastaavat elementit. Poista suodatin klikkamalla roskakoria.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/fil/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/fil/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/fil/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/fil/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Mga Setting", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Bumuo", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Tungkol", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "moda nang pagsasala", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Magulat ng problema sa website na ito", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Mga rehiyon o wika", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Talaan ng mga pagbabago", "description": "" @@ -104,77 +124,73 @@ "description": "Shown in the About pane" }, "supportS6H": { - "message": "Report a filter issue", + "message": "Magulat ng problema sa filter ", "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS3P1": { - "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", + "message": "Magreklamo dito ng mga isyu sa filter sa mga website: uBlockOrigin/uAssets issue tracker. Nangangailangan ng account sa GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Inpormasyon para sa troubleshooting", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "Upang hindi makagambala ng mga volunteer sa mga umuulit na ulat, pakisigurado na hindi pa narereklamo ang iyong isyu. Paalala: Mapapadala sa Github ang origin ng page na ito pagpindot dito.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Maghanap ng katulad ng ulat sa GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { - "message": "Address of the webpage:", + "message": "Lokasyon ng webpage:", "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "The webpage…", + "message": "Ang webpage", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { - "message": "-- Pick an entry --", + "message": "-- Mamili --", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { - "message": "Shows ads or ad leftovers", + "message": "Nagpapakita ng ads o mga bakas ng ads", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "Has overlays or other nuisances", + "message": "May mga overlay o iba pang harang", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { - "message": "Detects uBO Lite", + "message": "Nakadedetect ng uBO Lite", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { - "message": "Has privacy-related issues", + "message": "May mga isyu sa privacy", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "Malfunctions when uBO Lite is enabled", + "message": "Hindi gumagana nang maayos kapag nakabukas ang uBO Lite", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { - "message": "Opens unwanted tabs or windows", + "message": "Nagbubukas ng mga hindi kailangang tab o window", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { - "message": "Leads to badware, phishing", + "message": "Patungo sa badware o phishing", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { - "message": "Label the webpage as “NSFW” (“Not Safe For Work”)", + "message": "Markahan ang webpage na \"NSFW\" (“Not Safe For Work”)", "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Gumawa ng bagong ulat sa Github", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Mabuhay", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Maligayang pagdating sa uBO Lite. Dito mo mapipili ang default na mode sa pagfi-filter para sa lahat ng mga website.\n\nAng default na mode ay Basic dahil hindi nito kailangan ng karagdagang pahintulot na magbasa at magbago ng datos. Pwede mong pahintulutan ang uBO Lite, kung nagtitiwala ka sa amin, na basahin at baguhin ang data ng lahat ng mga website para sa karagdagang kakayahan sa pagfi-filter.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Default na mode sa pagfi-filter", "description": "The header text for the default filtering mode section" @@ -212,11 +228,11 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of websites for which no filtering will take place.", + "message": "Listahan ng mga website kung saan walang magagawang filtering. ", "description": "A short description for the editable field which lists trusted sites" }, "noFilteringModePlaceholder": { - "message": "[hostnames only]\nexample.com\ngames.example\n...", + "message": "[hostnames lamang]\nexample.com\ngames.example \n...", "description": "Default text for in edit field" }, "behaviorSectionLabel": { @@ -228,55 +244,171 @@ "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { - "message": "Show the number of blocked requests on the toolbar icon", + "message": "Ipakita ang dami ng napigilang mga request sa toolbar na icon", "description": "Label for a checkbox in the options page" }, "enableStrictBlockLabel": { - "message": "Enable strict blocking", + "message": "Paganahin ang striktong pagharang", "description": "Label for a checkbox in the options page" }, "enableStrictBlockLegend": { - "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "message": "Haharangan ang pagpunta sa mga hindi nais na mga site, at bibigyan ka ng pagkakataon na magpatuloy.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Nagbibigay ng mga katangian para sa mga teknikal na gumagamit.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { - "message": "Find lists", + "message": "Maghanap ng mga listahan", "description": "Placeholder for the input field used to find lists" }, "strictblockTitle": { - "message": "Page blocked", + "message": "Nakaharang na page", "description": "Webpage title for the strict-blocked page" }, "strictblockSentence1": { - "message": "uBO Lite has prevented the following page from loading:", + "message": "Hindi pinayagan ng uBO Lite ang pagpunta sa page dahil:", "description": "Sentence used in the strict-blocked page" }, "strictblockReasonSentence1": { - "message": "The page was blocked because of a matching filter in {{listname}}.", + "message": "Hinarang ang page na ito dahil sa isang filter sa {{listname}}", "description": "Text informing about what is causing the page to be blocked" }, "strictblockRedirectSentence1": { - "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", + "message": "Nais magpatuloy ng page na ito sa isa pang site. Kung magpapatuloy ka, dadalhin ka sa: {{url}}", "description": "Text warning about an incoming redirect" }, "strictblockNoParamsPrompt": { - "message": "without parameters", + "message": "walang mga parameter", "description": "Label to be used for the parameter-less URL" }, "strictblockBack": { - "message": "Go back", + "message": "Bumalik", "description": "A button to go back to the previous webpage" }, "strictblockClose": { - "message": "Close this window", + "message": "Isara ang window na ito", "description": "A button to close the current tab" }, "strictblockDontWarn": { - "message": "Don't warn me again about this site", + "message": "Huwag mo na akong balaan tungkol sa site na ito", "description": "Label for checkbox in document-blocked page" }, "strictblockProceed": { - "message": "Proceed", + "message": "Magpatuloy", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Paganahin ang element zapper mode", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Umalis sa element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "I-save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Ibalik", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "I-import at idagdag...", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "I-export...", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Dami ng mga nakaregister na patakaran: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/fr/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/fr/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/fr/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/fr/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Un bloqueur de contenu sans permission requise. Bloque les publicités, pisteurs, mineurs et plus dès l'installation.", + "message": "Un bloqueur de contenu efficace. Bloque les publicités, pisteurs, mineurs et plus dès l'installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Paramètres", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Filtres personnalisés", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Développement", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "À propos", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "Mode de filtrage", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Sur ce site Web", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Rapporter un problème sur ce site Web", + "message": "Rapporter un problème", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Régions, langues", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Importer / Exporter", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Coller ici les filtres cosmétiques spécifiques à ajouter", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Journal des changements", "description": "" @@ -111,12 +131,16 @@ "message": "Rapportez des problèmes de filtre sur des sites Web spécifiques dans le uBlockOrigin/uAssets suivi des problèmes. Nécessite un compte GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Informations de dépannage", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Pour éviter d'encombrer les contributeurs avec des rapports en double, veuillez vérifier que le problème n'a pas déjà été rapporté.", + "message": "Pour éviter d'encombrer les contributeurs avec des rapports en double, veuillez vérifier que le problème n'a pas déjà été rapporté.\nNote : Cliquer sur le bouton entraînera l'envoi de la page d'origine à GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Trouver des rapports similaires", + "message": "Trouver des rapports similaires sur GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Créer un nouveau rapport", + "message": "Créer un nouveau rapport sur GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Bienvenue", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Vous venez d'installer uBO Lite. À présent vous pouvez choisir le mode de filtrage par défaut à utiliser sur tous les sites Web.\n\nPar défaut, le mode Basique est sélectionné car il ne requiert pas de permissions pour lire et modifier les données. Si vous faites confiance à uBO Lite, vous pouvez lui donner des permissions étendues pour lire et modifier les données sur tous les sites Web pour activer des capacités de filtrage plus avancées pour tous les sites Web par défaut.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Mode de filtrage par défaut", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "La navigation vers des sites potentiellement indésirables sera bloquée, et vous aurez la possibilité de continuer", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Mode développeur", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Active l'accès aux fonctionnalités adaptées aux utilisateurs techniques.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Sauvegarde", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Sauvegardez vos paramètres personnalisés dans un fichier, ou restaurez vos paramètres personnalisés depuis un fichier.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "La restauration remplacera tous vos paramètres personnalisés actuels.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Trouver des listes", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Continuer", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Supprimer un élément", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Quitter le mode Zappeur d'élément", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Créer un filtre personnalisé", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Supprimer un filtre personnalisé", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Vue :", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Détails du mode de filtrage", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Règles DNR personnalisées", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Règles DNR de ", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Règles dynamiques", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Règles de session", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Enregistrer", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Rétablir", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Ajouter", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Importer", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exporter", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Sauvegarder…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restaurer…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Ne pas ajouter de contenu provenant de sources non fiables", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Nombre de règles enregistrées : {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Déplacez le curseur pour sélectionner la meilleure correspondance", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Cibler", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Aperçu", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Créer", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Choisissez un filtre ci-dessous pour surligner les éléments correspondants dans la page Web. Cliquez sur l'icône de poubelle pour supprimer un filtre.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/fy/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/fy/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/fy/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/fy/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "In eksperimintele, tastimmingsleaze ynhâldsblokkearder. Blokkearret daliks nei ynstallaasje advertinsjes, trackers, miners en mear.", + "message": "In, tastimmingsleaze ynhâldsblokkearder. Blokkearret daliks nei ynstallaasje advertinsjes, trackers, miners en mear.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Ynstellingen", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Oanpaste filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Untwikkelje", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Oer", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtermodus", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Op dizze website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "In probleem op dizze website melde", + "message": "In probleem melde", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -60,7 +72,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malwaredomeinen", + "message": "Beskerming tsjin malware, befeiliging", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -75,6 +87,14 @@ "message": "Gebieden, talen", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Ymportearje / Eksportearje", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Plak hjir spesifike kosmetyske filters om ta te foegjen", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Wizigingslochboek", "description": "" @@ -111,6 +131,10 @@ "message": "Meld filterproblemen mei spesifike websites yn de uBlockOrigin/uAssets-probleemtracker. Fereasket in GitHub-account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Probleemoplossingsynformaasje", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { "message": "Kontrolearje oft it probleem net earder meld is om foar te kommen dat frijwilligers mei dûbele meldingen belêst wurde.", "description": "A paragraph in the filter issue reporter section" @@ -167,14 +191,6 @@ "message": "Nije melding meitsje", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Wolkom", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Jo hawwe sakrekt uBO Lite ynstallearre. Hjir kinne jo de standery filtermodus foar it gebrûk op alle websites kieze.\n\nStandert wurdt de modus Basis selektearre, omdat hjirfoar gjin tastimming foar it lêzen en wizigjen fan gegevens fereaske is. As jo uBO Lite fertrouwe, kinne jo it brede tastimming foar it lêzen en wizigjen fan gegevens op alle websites ferliene, sadat standert mear avansearre filtermooglikheden foar alle websites beskikber binne.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Standert filtermodus", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigaasje nei potinsjeel net-winske websites wurdt blokkearre, en jo krije de opsje om troch te gean.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Untwikkelersmodus", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Skeakelet tagong ta foar technyske brûkers geskikte funksjes yn.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Reservekopy", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Meitsje i reservekopy fan jo oanpaste ynstellingen neiei bestân, of set jo oanpaste ynstellingen werom fan in bestân út.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Weromsette oerskriuwt al jo aktuele oanpaste ynstellingen.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Listen sykje", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Tochgean", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "In elemint­ fuortsmite", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Elemint­wisker­modus slute", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "In oanpast filter meitsje", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "In oanpast filter fuortsmite", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Werjefte:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Details fan filtermodus", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Oanpaste DNR-regels", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR-regels fan …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamyske regelset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Sesjeregelset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Bewarje", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Ungedien meitsje", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Tafoegje", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Ymportearje en tafoegje…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Eksportearje…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Reservekopy meitje…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Weromsette…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Foegje gjin ynhâld fan net-fertroude boarnen ta.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Oantal registrearre regels: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Ferpleats de skowregeler foar de beste oerienkomst", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Kieze", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Foarbyld", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Oanmeitsje", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Selektearje hjirûnder in filter om oerienkommende eleminten yn de webside te markearjen. Klik op it jiskefet om in filter fuort te smiten.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/gl/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/gl/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/gl/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/gl/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Axustes", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Filtros persoais", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Desenvolvemento", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Acerca de", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "modo de filtrado", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Neste sitio web", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "Informar dun problema nesta web", "description": "Tooltip used for the 'chat' icon in the panel" @@ -60,7 +72,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware protection, security", + "message": "Protección contra malware, seguridade", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -72,9 +84,17 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupRegions": { - "message": "Rexións, linguaxes", + "message": "Rexións, linguas", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Importar/Exportar", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Pega aquí os filtros cosméticos a engadir", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Rexistro de cambios", "description": "" @@ -111,8 +131,12 @@ "message": "Informa de problemas cos filtros en webs concretas no seguimento de problemas en uBlockOrigin/uAssets. Require unha conta GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Información para arranxar problemas", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Para evitar a sobrecarga de traballo para as persoas voluntarias con duplicados dos problemas, comproba que aínda non se informou acerca do problema.", + "message": "Para evitar a sobrecarga de traballo para as persoas voluntarias con duplicados dos problemas, comproba que aínda non se informou sobre o problema. Nota: ao premer no botón enviarás a orixe da páxina a GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { @@ -167,14 +191,6 @@ "message": "Crear nova denuncia", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Benvida", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Acabas de instalar uBO Lite. Aquí podes escoller o modo de filtrado para usar en todas as páxinas web.\n\nPor defecto, o modo Básico está seleccionado porque non require o permiso de lectura ou modificar datos. Se confías en uBO Lite, podes darlle máis permisos para ler e modificar os datos de todos os sitios web para poder realizar por defecto un filtrado máis preciso en todas as páxinas web.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Modo de filtrado por defecto", "description": "The header text for the default filtering mode section" @@ -204,7 +220,7 @@ "description": "This describes the 'basic' filtering mode" }, "optimalFilteringModeDescription": { - "message": "Filtrado avanzado da rede e filtrado extendido específico usando listas de filtrado seleccionadas.\n\nRequire permisos máis amplos para ler e modificar datos en todas as webs.", + "message": "Filtrado avanzado da rede e filtrado estendido específico usando listas de filtrado seleccionadas.\n\nRequire permisos máis amplos para ler e modificar datos en todas as webs.", "description": "This describes the 'optimal' filtering mode" }, "completeFilteringModeDescription": { @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Vaise bloquear a navegación en webs potencialmente non desexables, e ofrecerase a opción de bloquealas.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Modo desenvolvemento", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Permitir acceso a funcións pensadas para persoas con experiencia técnica.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Copia de apoio", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Garda nun ficheiro a túa configuración ou restablece os axustes desde un ficheiro.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Ao restablecer vas sobrescribir a configuración actual.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Atopa listas", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceder", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Entrar no modo eliminador de elementos", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Sair do modo eliminador de elementos", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Crear un filtro personalizado", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Retirar un filtro personalizado", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Ver:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Detalles do modo de filtrado", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Regras DNR persoais", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Regras DNR de…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Conxunto de regras dinámicas", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Conxunto de regras de sesión", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Gardar", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Reverter", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Engadir", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Importar e engadir…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exportar…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Gardar axustes…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restablecer…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Non engadir contido desde orixes non fiables", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Número de regras rexistradas: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move o desprazador para elixir a mellor concordancia", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Elixir", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Vista previa", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Crear", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Escolle un filtro para destacar os elementos que representa na páxina web. Preme no caldeiro do lixo para eliminar un filtro.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/gu/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/gu/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/gu/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/gu/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "A permission-less content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", + "message": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Report an issue", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Regions, languages", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Changelog", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/he/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/he/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/he/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/he/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "הגדרות", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "מסננים בהתאמה אישית", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "פיתוח", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "על אודות", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "מצב מסנן", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "באתר זה", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "דווח על בעיה באתר זה", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "אזורים, שפות", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "יבוא / יצוא", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "העתיקו לכאן מסננים קוסמטים ספציפים לשם הוספה", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "יומן שינויים", "description": "" @@ -111,6 +131,10 @@ "message": "לדיווח על בעיות באתרים ספציפים יש לפתוח דיווח חדש במעקב הדיווחים של uBlockOrigin/uAssets. נדרש חשבון ב GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "מידע לפתרון בעיות", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { "message": "כדי להימנע מהכבדה על מתנדבים בדווחים כפולים, נא לודא שבעיה דומה טרם דווחה.", "description": "A paragraph in the filter issue reporter section" @@ -167,14 +191,6 @@ "message": "צור דיווח חדש", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "ברוך בואך", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "התקנת uBO Lite הסתיימה זה עתה. ניתן לבחור כאן את אופן סינון ברירת המחדל בכל אתרי הרשת.\n\nכברירת מחדל, ייבחר אופן סינון בסיסי מאחר והוא אינו דורש הרשאות קריאה ושינוי נתונים. 'סומכים על uBO Lite?' אם כן, ניתן להעניק ל־uBO Lite הרשאות נרחבות לכתיבה ושינוי נתונים בכלול אתרי הרשת על מנת לאפשר יכולות סינון מתקדמות יותר כבררת מחדל.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "מצב סינון ברירת מחדל", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "ניווט אפשרי לאתרים לא רצויים יחסם ותהיה אפשרות להחליט להמשיך.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "מצב מפתחים", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "מאפשר גישה ליכולות עבור משתמשים טכניים.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "גיבוי / שחזור", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "גיבוי של ההגדרות האישיות לקובץ, או שחזור של ההגדרות האישיות מקובץ.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "השחזור יחליף את כל ההגדרות האישיות הנוכחיות.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "חיפוש רשימות", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "המשך", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "הסר אלמנט", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "צא ממצב מחיקת אלמנטים", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "יצירת מסנן מותאם אישית", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "מחיקת מסנן מותאם אישית", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "הצג", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "פרטי מצב סינון", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "חוקי DNR אישיים", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "חוקי DNR של...", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "קבוצת חוקים דינמיים", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "קבוצת חוקי מפגש (session)", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "שמירה", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "ביטול שינויים", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "הוספה", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "ייבא וצרף…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "ייצוא…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "גיבוי…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "שחזור…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "אל תוסיפו תוכן ממקורות לא מהיימנים", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "מספר החוקים שנרשמו: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "הזיזו את המחוג לבחירת ההתאמה הטובה ביותר", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "בחירה", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "תצוגה מקדימה", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "יצירה", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "בחרו את המסנן למטה להצגת הרכיבים התואמים בדף האינטרנט. לחצו על פח האשפה למחיקת המסנן.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/hi/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/hi/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/hi/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/hi/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "सेटिंग्स", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "विकास", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "जानकारी", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "फ़िल्टरिंग मोड", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "इस वेबसाइट पर", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "इस वेबसाइट पर किसी समस्या को रिपोर्ट करें", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "क्षेत्र, भाषाएँ", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "परिवर्तन पत्र", "description": "" @@ -104,59 +124,63 @@ "description": "Shown in the About pane" }, "supportS6H": { - "message": "Report a filter issue", + "message": "फ़िल्टर समस्या को रिपोर्ट करें", "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS3P1": { - "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", + "message": "विशिष्ट वेबसाइट पर फ़िल्टर समस्या को uBlockOrigin/uAssets समस्या ट्रैकर पर रिपोर्ट करें. इसके लिए एक GitHub खाते की आवश्यकता होगी.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "समस्या निवारक जानकारी", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "GitHub पर मिलती-जुलती रिपोर्ट खोजें", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { - "message": "Address of the webpage:", + "message": "वेब पेज का पता:", "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "The webpage…", + "message": "वेब पेज…", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { - "message": "-- Pick an entry --", + "message": "-- एक प्रविष्टि चुनें --", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { - "message": "Shows ads or ad leftovers", + "message": "विज्ञापनों को या शेष बचे विज्ञापन को दिखाता है", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "Has overlays or other nuisances", + "message": "ओवरले या कोई अन्य दिक्कतें हैं", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { - "message": "Detects uBO Lite", + "message": "यह uBO Lite की पहचान करता है", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { - "message": "Has privacy-related issues", + "message": "गोपनीयता से संबंधित समस्याएं हैं", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "Malfunctions when uBO Lite is enabled", + "message": "यह uBO Lite सक्षम होने पर ठीक से काम नहीं करता", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { - "message": "Opens unwanted tabs or windows", + "message": "अवांछित टैब या विंडो खोलता है", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { - "message": "Leads to badware, phishing", + "message": "बैडवेयर, फ़िशिंग की ओर ले जाता है", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "स्वागत", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "आपने अभी-अभी uBO Lite स्थापित किया है. आप यहां सभी वेबसाइटों पर उपयोग करने के लिए डिफ़ॉल्ट फ़िल्टरिंग मोड चुन सकते हैं.\n\nडिफ़ॉल्ट रूप से, बुनियादी मोड चुना जाता है क्योंकि इसमें डेटा को पढ़ने और बदलने की अनुमति की आवश्यकता नहीं होती है. यदि आप uBO Lite पर भरोसा करते हैं, तो आप डिफ़ॉल्ट रूप से सभी वेबसाइटों के लिए अधिक उन्नत फ़िल्टरिंग क्षमताओं को सक्षम करने के लिए सभी वेबसाइटों पर डेटा को पढ़ने और बदलने की व्यापक अनुमति दे सकते हैं.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "डिफ़ॉल्ट फ़िल्टरिंग मोड", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "देखें:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "सहेजें", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "पूर्ववत", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "इम्पोर्ट करें और जोड़ें…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "निर्यात…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "अविश्वसनीय स्रोतों से सामग्री न जोड़ें", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/hr/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/hr/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/hr/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/hr/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Bloker sadržaja bez dopuštenja. Blokira oglase, oglasne pratitelje, kripto \"rudare\" i ostalo odmah nakon instalacije.", + "message": "Učinkovit blokator sadržaja. Blokira oglase, oglasne pratitelje, kripto \"rudare\" i ostalo odmah nakon instalacije.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Postavke", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Prilagođeni filteri", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Razvoj", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "O aplikaciji", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "Način filtriranja", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": " Na ovoj web stranici", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Prijavite problem na ovoj web stranici", + "message": "Prijavi problem", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -60,7 +72,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Zloćudne domene", + "message": "Zaštita od zlonamjernog softvera, sigurnost", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -75,6 +87,14 @@ "message": "Regije, jezici", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Uvoz / Izvoz", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Ovdje zalijepite određene vizualne filtere koje želite dodati", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Popis promjena", "description": "" @@ -111,12 +131,16 @@ "message": "Prijavite probleme s filtrima s određenim web-lokacijama uBlockOrigin/uAssets alatu za praćenje problema. Potreban je GitHub račun.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Informacije o rješavanju problema", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Kako biste izbjegli opterećivanje volontera duplim prijavama, provjerite nije li problem već prijavljen.", + "message": "Kako biste izbjegli opterećivanje volontera duplim prijavama, provjerite nije li problem već prijavljen. Napomena: klik na gumb uzrokovat će slanje izvorne stranice na GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Nađi slične prijave", + "message": "Nađi slične prijave na GitHub-u", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Napravi novu prijavu", + "message": "Napravi novu prijavu na GitHub-u", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Dobrodošli", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Upravo ste instalirali uBO Lite. Ovdje možete odabrati zadani način filtriranja za korištenje na svim web stranicama.\n\nPrema zadanim postavkama odabran je način rada Osnovni jer ne zahtijeva dopuštenje za čitanje i promjenu podataka. Ako vjerujete uBO Liteu, možete mu dati široko dopuštenje za čitanje i promjenu podataka na svim web stranicama kako biste prema zadanim postavkama omogućili naprednije mogućnosti filtriranja za sva web mjesta.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Zadani način filtriranja", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigacija do potencijalno nepoželjnih stranica bit će blokirana i bit će vam ponuđena opcija za nastavak.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Način rada za programere", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Omogućuje pristup značajkama prikladnim za tehničke korisnike.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Sigurnosna kopija", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Napravite sigurnosnu kopiju prilagođenih postavki u datoteku ili ih vratite iz datoteke.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Vraćanje će prebrisati sve vaše trenutne prilagođene postavke.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Pronađi liste", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Nastavi", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Ukloni element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Zatvori način rada uklanjanja elementa", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Napravi prilagođeni filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Ukloni prilagođeni filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Pregled:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Detalji načina filtriranja", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Prilagođena pravila DNR-a", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR pravila …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dinamički skup pravila", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Skup pravila sesije", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Spremi", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Poništi", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Dodaj", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Uvesti i dodati...", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Izvoz...", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Sigurnosno kopiranje…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Vraćanje…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Ne dodavajte sadržaj iz nepouzdanih izvora", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Broj registriranih pravila: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Pomaknite klizač za odabir najboljeg podudaranja", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Odaberi", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Pregled", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Napravi", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Odaberite filter u nastavku kako biste istaknuli odgovarajuće elemente na web stranici. Kliknite koš za smeće kako biste uklonili filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/hu/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/hu/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/hu/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/hu/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Beállítások", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Saját szűrők", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Fejlesztés", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Névjegy", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "szűrési mód", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Ezen a weboldalon", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "Oldalon lévő probléma jelentése", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "Régiók, nyelvek", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Importálás/exportálás", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Illessze be ide a hozzáadandó kozmetikai szűrőket", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Változások listája", "description": "" @@ -111,8 +131,12 @@ "message": "Az adott webhelyeket érintő szűrőhibákat a uBlockOrigin/uAssets hibakövetőjében jelentse. Ehhez GitHub-fiók szükséges.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Hibakeresési információk", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Az önkéntesek terhelésének csökkentése érdekében győződjön meg róla, hogy a hiba még nem lett jelentve.", + "message": "Az önkéntesek terhelésének csökkentése érdekében győződjön meg róla, hogy a hiba még nem lett jelentve. Megjegyzés: a gombra kattintás azt okozza, hogy a lap eredete el lesz küldve a GitHub részére.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Új jelentés létrehozása", + "message": "Új jelentés létrehozása GitHub-ra", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Üdvözöljük", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Most telepítette a uBO Lite-ot. Itt választhatja ki az összes weboldalon használandó alapértelmezett szűrési módot.\n\nAlapértelmezés szerint az Alapvetú mód van kiválasztva, mert nem igényel engedélyt az adatok olvasásához és módosításához. Ha megbízik az uBO Lite-ban, széles körű engedélyt adhat neki az adatok olvasására és módosítására az összes webhelyen, hogy alapértelmezés szerint fejlettebb szűrési lehetőségeket tegyen lehetővé minden webhelyen.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Alapértelmezett szűrési mód", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Az esetleges nem kívánatos webhelyekre való navigáció blokkolva lesz, és rákérdez arra, hogy folytatja-e.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Fejlesztői mód", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Hozzáférést biztosít a képzettebb felhasználóknak való funkciókhoz.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Biztonsági mentés", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Egyéni beállítások fájlbamentése, vagy az egyéni beállítások helyreállítása egy fájlból.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "A helyreállítás felülírja a jelenlegi egyéni beállításokat.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Listák keresése", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Folytatás", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Belépés az elemeltávolító módba", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Kilépés az elemeltávolító módból", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Egyéni szűrő létrehozása", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Egyéni szűrő eltávolítása", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Nézet:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Szűrési mód részletei", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Egyéni DNR szabályok", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR szabályok ehhez…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dinamikus szabálykészlet", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Munkamenet szabálykészlete", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Mentés", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Visszaállítás", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Hozzáadás", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Importálás és hozzáadás…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exportálás…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Biztonsági mentés…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Helyreállítás…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Ne adjon hozzá megbízhatatlan forrásokból származó tartalmat.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Regisztrált szabályok száma: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Használja a csúszkát a legjobb egyezés kiválasztásához", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Kiválasztás", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Előnézet", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Létrehozás", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Válasszon alább egy szűrőt, hogy kiemelje az egyező elemeket a weboldalon. Kattintson a kuka ikonra egy szűrő eltávolításához.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/hy/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/hy/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/hy/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/hy/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Կարգավորումներ", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Ընդլայնման մասին", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "զտման ռեժիմ", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Զեկուցել կայքի հետ խնդրի մասին", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Տարածաշրջաններ, լեզուներ", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Փոփոխությունների մատյան", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -124,7 +148,7 @@ "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "The webpage…", + "message": "Վեբկայքը՝", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Բարի գալուստ", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Դուք հենց նոր տեղադրեցիք uBO Lite-ը։ Այստեղ Դուք կարող եք զտման ստանդարտ ռեժիմ ընտրել բոլոր կայքերի համար։\n\nԼռելյայն կերպով ընտրված է հիմնական ռեժիմը, քանի որ այն չի պահանջում տվյալների ընթերցման և փոփոխման թույլտվություն։ Եթե վստահում եք uBO Lite-ին, կարող եք տալ դրան բոլոր կայքերում տվյալների ընթերցման և փոփոխման լայն իրավունքներ՝ բոլոր կայքերի համար զտման ավելի առաջադեմ հնարավորությունները լռելյայն կերպով միացնելու համար։", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Զտման լռելյայն ռեժիմ", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -264,11 +300,11 @@ "description": "Label to be used for the parameter-less URL" }, "strictblockBack": { - "message": "Go back", + "message": "Հետ գնալ", "description": "A button to go back to the previous webpage" }, "strictblockClose": { - "message": "Close this window", + "message": "Փակել այս պատուհանը", "description": "A button to close the current tab" }, "strictblockDontWarn": { @@ -276,7 +312,103 @@ "description": "Label for checkbox in document-blocked page" }, "strictblockProceed": { - "message": "Proceed", + "message": "Շարունակել", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/id/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/id/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/id/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/id/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Pengaturan", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Mengembangkan", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Tentang", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "mode filter", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Di situs ini", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "Laporkan masalah pada situs ini", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "Wilayah, bahasa", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Catatan perubahan", "description": "" @@ -111,6 +131,10 @@ "message": "Laporkan masalah filter situs web tertentu ke pelacak masalah uBlockOrigin/uAssets. Membutuhkan akun GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Informasi pemecahan masalah", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { "message": "Untuk menghindari membebani sukarelawan dengan laporan duplikat, harap verifikasi bahwa masalah tersebut belum dilaporkan.", "description": "A paragraph in the filter issue reporter section" @@ -167,14 +191,6 @@ "message": "Buat laporan baru", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Selamat datang", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Terima kasih telah memasang uBO Lite. Anda bisa memilih di sini mode filter bawaan untuk digunakan pada semua situs web.\n\nSecara bawaan, mode Dasar akan dipilih karena tidak membutuhkan izin untuk membaca dan mengubah data. Jika Anda mempercayai uBO Lite, Anda bisa memberikan izin tambahan untuk membaca dan mengubah data pada semua situs web untuk mengaktifkan kemampuan filter yang lebih luas untuk semua situs web secara bawaan.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Mode filter bawaan", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigasi ke situs yang mungkin tidak diinginkan akan diblokir, dan Anda akan ditawari opsi untuk melanjutkan.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Mode pengembang", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Mengaktifkan akses ke fitur yang sesuai untuk pengguna teknis.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Temukan daftar", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Lanjutkan", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Masuk ke mode penghapus elemen", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Keluar dari mode penghapus elemen", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Buat filter khusus", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Hapus filter khusus", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Melihat", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Detail mode penyaringan", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Aturan DNR khusus", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Aturan DNR tentang …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Aturan dinamis ", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Aturan sesi", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Simpan", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Kembalikan", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Impor dan tambahkan…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Ekspor…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Jangan tambahkan konten dari sumber tidak terpercaya", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Jumlah aturan yang terdaftar: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Pindahkan penggeser untuk memilih kecocokan terbaik", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pilih", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Pratinjau", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Buat", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Pilih filter di bawah ini untuk menyorot elemen yang cocok di halaman web. Klik ikon tempat sampah untuk menghapus filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/it/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/it/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/it/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/it/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Un blocco sperimentale che non richiede permessi. Blocca pubblicità, tracker, cryptominer e altro ancora.", + "message": "Un efficiente bloccatore dei contenuti. Blocca annunci, tracker, minatori e altro ancora subito dopo l'installazione.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -12,51 +12,63 @@ "description": "Appears aside each filter list in the _3rd-party filters_ pane" }, "dashboardName": { - "message": "uBO Lite — Pannello di controllo", + "message": "uBO Lite — Cruscotto", "description": "English: uBO Lite — Dashboard" }, "settingsPageName": { "message": "Impostazioni", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Filtri personalizzati", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Sviluppo", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Informazioni", "description": "appears as tab name in dashboard" }, "aboutPrivacyPolicy": { - "message": "Informativa sulla privacy", + "message": "Politica di riservatezza", "description": "Link to privacy policy on GitHub (English)" }, "popupFilteringModeLabel": { "message": "Modalità di filtraggio", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "In questo sito web", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Segnala un problema su questo sito web", + "message": "Segnala un problema con questo sito", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { - "message": "Apri il pannello di controllo", + "message": "Apri il cruscotto", "description": "English: Click to open the dashboard" }, "popupMoreButton": { - "message": "Altro", + "message": "Più", "description": "Label to be used to show popup panel sections" }, "popupLessButton": { - "message": "Nascondi", + "message": "Meno", "description": "Label to be used to hide popup panel sections" }, "3pGroupDefault": { - "message": "Predefiniti", + "message": "Predefinite", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAds": { - "message": "Pubblicità", + "message": "Inserz.", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupPrivacy": { - "message": "Privacy", + "message": "Riservatezza", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { @@ -64,19 +76,27 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { - "message": "Elementi fastidiosi", + "message": "Scocciature", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMisc": { - "message": "Varie", + "message": "Vari", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupRegions": { - "message": "Regioni, lingue", + "message": "Lingue e regioni", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Importa / Esporta", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Incolla qui i filtri cosmetici specifici da aggiungere", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { - "message": "Registro delle modifiche", + "message": "Reg. modifiche", "description": "" }, "aboutCode": { @@ -100,23 +120,27 @@ "description": "Link text to uBO's own filter lists repo" }, "aboutDependencies": { - "message": "Dipendenze esterne (GPLv3-compatibili):", + "message": "Dipendenze esterne (in linea con la GPL v3):", "description": "Shown in the About pane" }, "supportS6H": { - "message": "Segnala un problema di filtro", + "message": "Segnala un problema con un filtro", "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS3P1": { - "message": "Segnala i problemi di filtraggio con siti web specifici su uBlockOrigin/uAssets issue tracker. Richiede un account GitHub.", + "message": "Segnala i problemi di filtraggio con siti web specifici nel tracciatore problemi uBlockOrigin/uAssets. Richiede un account GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Informazioni sulla risoluzione dei problemi", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Per evitare di gravare sui volontari con segnalazioni doppie, verifica che il problema non sia già stato segnalato.", + "message": "Per evitare di gravare sui volontari con segnalazioni duplicate, verifica che il problema non sia già stato segnalato. Nota: cliccando il pulsante l'origine della pagina sarà inviata a GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Trova segnalazioni simili", + "message": "Trova segnalazioni simili in GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -128,15 +152,15 @@ "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { - "message": "Scegli una voce", + "message": "− Scegli una voce −", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { - "message": "Mostra pubblicità o avanzi di pubblicità", + "message": "Mostra inserzioni o loro residui", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "Presenta sovrapposizioni o altri disturbi", + "message": "Ha sovrapposizioni o altri fastidi", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { @@ -144,7 +168,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { - "message": "Ha problemi relativi alla privacy", + "message": "Ha problemi relativi alla riservatezza", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { @@ -164,23 +188,15 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Crea una nuova segnalazione", + "message": "Crea nuova segnalazione in GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Benvenuto", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Hai appena installato uBO Lite. Qui puoi scegliere la modalità di filtraggio predefinita da utilizzare su tutti i siti web.\n\nPer impostazione predefinita, viene selezionata la modalità Basilare, perché non richiede l'autorizzazione per leggere e modificare i dati. Se ti fidi di uBO Lite, puoi concedergli un'ampia autorizzazione per leggere e modificare i dati su tutti i siti web, in modo da abilitare capacitità di filtraggio più avanzate per tutti i siti web in modo predefinito.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Modalità di filtraggio predefinita", "description": "The header text for the default filtering mode section" }, "defaultFilteringModeDescription": { - "message": "La modalità di filtraggio predefinita sarà sovrascritta dalle modalità di filtraggio per sito web. È possibile regolare la modalità di filtraggio su un determinato sito web in base alla modalità che funziona meglio su quel sito. Ogni modalità presenta vantaggi e svantaggi.", + "message": "La modalità di filtraggio predefinita sarà sovrascritta dalle modalità di filtraggio per sito web. È possibile regolare la modalità di filtraggio in un determinato sito web in base alla modalità che funziona meglio per quel sito. Ogni modalità presenta vantaggi e svantaggi.", "description": "This describes the default filtering mode setting" }, "filteringMode0Name": { @@ -200,15 +216,15 @@ "description": "Name of blocking mode 3" }, "basicFilteringModeDescription": { - "message": "Filtraggio di rete di base da liste di filtri selezionate.\n\nNon richiede l'autorizzazione per leggere e modificare i dati sui siti web.", + "message": "Filtraggio di rete di base da liste di filtri selezionate.\n\nNon richiede l'autorizzazione per leggere e modificare i dati nei siti web.", "description": "This describes the 'basic' filtering mode" }, "optimalFilteringModeDescription": { - "message": "Filtraggio di rete avanzato più un filtraggio esteso specifico da liste di filtri selezionate.\n\nRichiede un'ampia autorizzazione per leggere e modificare i dati su tutti i siti web.", + "message": "Filtraggio di rete avanzato più un filtraggio esteso specifico da liste di filtri selezionate.\n\nRichiede un'ampia autorizzazione per leggere e modificare i dati in tutti i siti web.", "description": "This describes the 'optimal' filtering mode" }, "completeFilteringModeDescription": { - "message": "Filtraggio di rete avanzato più un filtraggio esteso specifico e generico da liste di filtri selezionate.\n\nRichiede un'ampia autorizzazione per leggere e modificare i dati su tutti i siti web.\n\nIl filtraggio esteso generico può causare un maggiore utilizzo delle risorse della pagina web.", + "message": "Filtraggio di rete avanzato più un filtraggio esteso specifico e generico da liste di filtri selezionate.\n\nRichiede un'ampia autorizzazione per leggere e modificare i dati in tutti i siti web.\n\nIl filtraggio esteso generico può causare un maggiore uso delle risorse della pagina web.", "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "La navigazione verso siti potenzialmente indesiderati verrà bloccata e ti verrà offerta la possibilità di procedere.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Modalità sviluppatore", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Abilita l'accesso a funzioni adatte a utenti tecnici.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Copia le impostazioni personali in un file, o rimuovile da un file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Il ripristino sovrascriverà le impostazioni personali in uso.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Trova elenchi", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Procedi", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Accedi alla modalità blocco rapido", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Esci dalla modalità blocco rapido", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Crea un filtro personalizzato", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Rimuovi un filtro personalizzato", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Vista:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Dettagli modalità filtraggio", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Regole DNR personali", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Regole DNR per …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Gruppo regole dinamiche", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Gruppo regole di sessione", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Salva", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Ritorna", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Aggiungi", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Importa e accoda…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Esporta…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Copia…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Ripristina…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Non aggiungere contenuti da fonti non affidabili", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Numero di regole registrate: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Sposta il cursore per selezionare la corrispondenza migliore", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Scegli", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Anteprima", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Crea", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Seleziona un filtro per evidenziare gli elementi corrispondenti nella pagina web. Clicca il cestino per rimuovere un filtro.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ja/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ja/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ja/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ja/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "設定", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "開発", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "uBO Lite について", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "フィルタリングモード", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "このサイト上で", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "このサイト上での問題を報告", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "地域・言語", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "更新履歴", "description": "" @@ -111,8 +131,12 @@ "message": "uBlockOrigin/uAssets issue tracker で特定のウェブサイトでのフィルターの問題を報告します。GitHub アカウントが必要です", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "トラブルシューティング情報", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "重複した報告によってボランティアに負担をかけないように、問題がすでに報告されていないか確認してください。", + "message": "重複した報告によってボランティアに負担をかけないように、問題がすでに報告されていないか確認してください。 注意: ボタンをクリックすると、ページのオリジンが GitHub に送信されます。", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { @@ -167,14 +191,6 @@ "message": "新しい報告を作成", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "ようこそ", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "uBO Lite のインストールが完了しました。すべてのサイトに適用するデフォルトのフィルタリングモードを選んでください。\n\nデフォルトでは、データの読み書きの権限が必要ない基本モードが選択されています。 uBO Lite を信用する場合は、データの読み書きや変更の権限を許可して、すべてのサイトに対してより高度なフィルタリングを有効化できます。", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "デフォルトのフィルタリングモード", "description": "The header text for the default filtering mode section" @@ -237,10 +253,30 @@ }, "enableStrictBlockLegend": { "message": "望ましくない可能性のあるサイトへのナビゲーションはブロックされ、次に進むためのオプションが表示されます。", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "開発者モード", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "技術ユーザーに適した機能へのアクセスを有効にします。", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "バックアップ", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "カスタムした設定をファイルとしてバックアップしたり、ファイルからリストアしたりできます。", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "リストアすると現在のカスタムした設定がすべて上書きされます。", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { - "message": "Find lists", + "message": "リストを検索", "description": "Placeholder for the input field used to find lists" }, "strictblockTitle": { @@ -252,11 +288,11 @@ "description": "Sentence used in the strict-blocked page" }, "strictblockReasonSentence1": { - "message": "The page was blocked because of a matching filter in {{listname}}.", + "message": "このページは、{{listname}} のフィルターに一致したためブロックされました。", "description": "Text informing about what is causing the page to be blocked" }, "strictblockRedirectSentence1": { - "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", + "message": "ブロックしたページは別のサイトへリダイレクトしようとしています。続行すると次の URL へ移動します: {{url}}", "description": "Text warning about an incoming redirect" }, "strictblockNoParamsPrompt": { @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "続行する", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "要素抹消モードを開始", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "要素抹消モードを終了", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "カスタムフィルターの作成", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "カスタムフィルターの削除", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "表示:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "フィルタリングの詳細", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "独自DNRルール", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNRのルール...", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "動的ルールセット", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "セッションルールセット", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "保存", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "元に戻す", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "インポートと追加", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "エクスポート…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "バックアップ…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "リストア…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "信頼できないソースから追加しないでください。", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "登録されたルールの数: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "スライダーを動かして最適なものを選ぶ", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "取得", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "プレビュー", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "作成", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "下のフィルターを選択すると、ウェブページ内の一致する要素がハイライトされます。フィルタを削除するには、ゴミ箱をクリックしてください。", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ka/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ka/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ka/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ka/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "პარამეტრები", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "მორგებული ფილტრები", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "შემუშავება", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "შესახებ", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "გაფილტვრის რეჟიმი", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "ამ ვებსაიტზე", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "ამ საიტზე ხარვეზის მოხსენება", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "მხარეები, ენები", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "შემოტანა / გატანა", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "აქ ჩასვით გარეგნული ნაწილების ცალკეული ფილტრები დასამატებლად", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "ცვლილებები", "description": "" @@ -111,8 +131,12 @@ "message": "ცალკეულ საიტზე ფილტრების ხარვეზების მოსახსენებლად გამოიყენეთ uBlockOrigin/uAssets ხარვეზების აღსარიცხავი. დაგჭირდებათ GitHub-ანგარიში.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "მონაცემები ხარვეზის მოსაგვარებლად", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "მოხალისეები რომ არ მოცდნენ ერთნაირი მოსხენებების ნახვით, გთოხვთ გადაამოწმოთ, უკვე ხომ არაა გაგზავნილი საჩივარი ამ ხარვეზზე.", + "message": "მოხალისეები რომ არ მოცდნენ ერთნაირი მოსხენებების გაცნობით, გთხოვთ გადაამოწმოთ, უკვე ხომ არაა გაგზავნილი საჩივარი ამ ხარვეზზე. გაითვალისწინეთ: ღილაკზე დაწკაპების შედეგად გვერდის მონაცემები გაიგზავნება GitHub-ზე.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { @@ -167,14 +191,6 @@ "message": "შექმენით ახალი მოსხენება", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "მოგესალმებით", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "თქვენ ახლახან დააყენეთ uBO Lite. აქვე შეგიძლიათ აირჩიოთ ფილტრაციის ნაგულისხმევი რეჟიმი ყველა საიტზე გამოსაყენებლად.\n\nნაგულისხმევად ძირითადი რეჟიმია შერჩეული, ვინაიდან არ საჭიროებს მონაცემთა წაკითხვისა და ცვლილების ნებართვებს. თუ თქვენთვის სანდოა uBO Lite, შეგიძლიათ დართოთ მონაცემთა წაკითხვისა და შეცვლის ნება ყველა საიტზე გაუმჯობესებული ფილტრაციის ნაგულისხმევად გამოყენებისთვის.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "გაფილტვრის ნაგულისხმევი რეჟიმი", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "შეიზღუდა სავარაუდოდ არასასურველ გვერდებზე გადასვლა, საშუალება გეძლევათ, მაინც განაგრძოთ.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "შემმუშვებლის რეჟიმი", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "შესაძლებლობები გამოცდილი მომხმარებლებისთვის.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "მარქაფი", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "დაამარქაფეთ მითითებული პარამეტრები ფაილში ან აღადგინეთ ფაილიდან.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "აღდგენისას ყველა მიმდინარე პარამეტრი ჩანაცვლდება.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "სიების მოძიება", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "გაგრძელება", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "ნაწილების ამოჭრის რეჟიმში გადასვლა", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "ნაწილების ამოჭრის რეჟიმიდან გასვლა", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "მორგებული ფილტრის შექმნა", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "მორგებული ფილტრის მოცილება", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "ხედი:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "ფილტრის რეჟიმი ვრცლად", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "მორგებული DNR-წესები", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR-წესები…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "ცვალებადი წესების კრებული", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "სეანსის წესების კრებული", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "შენახვა", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "დაბრუნება", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "დამატება", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "შეტანა და დამატება…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "გატანა…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "დამარქფება…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "აღდგენა…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "ნუ დაამატებთ შიგთავსს არასანდო წყაროებიდან.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "დამოწმებული წესები სულ: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "გადაადგილეთ სრიალა უკეთ დამთხვევისთვის", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "აღება", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "შეთვალიერება", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "შექმნა", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "აირჩიეთ ქვემოთ ფილტრი შესაბამისი ნაწილების მოსანიშნად ვებგვერდზე. დაწკაპეთ სანაგვე ყუთი ფილტრის მოსაცილებლად.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/kk/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/kk/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/kk/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/kk/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "A permission-less content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", + "message": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Report an issue", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Regions, languages", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Changelog", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/kn/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/kn/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/kn/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/kn/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "ಸಂಯೋಜನೆಗಳು", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "ಬಗ್ಗೆ", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "ಫಿಲ್ಟರಿಂಗ್ ಮೋಡ್", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Report an issue", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "ಪ್ರದೇಶಗಳು, ಭಾಷೆಗಳು\n", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "ಬದಲಾವಣೆಗಳು", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "ಸ್ವಾಗತ", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "ನೀವು ಈಗಷ್ಟೇ uBO Lite ಅನ್ನು ಸ್ಥಾಪಿಸಿರುವಿರಿ. ಇಲ್ಲಿ ನೀವು ಎಲ್ಲಾ ವೆಬ್‌ಸೈಟ್‌ಗಳಲ್ಲಿ ಬಳಸಲು ಡಿಫಾಲ್ಟ್ ಫಿಲ್ಟರಿಂಗ್ ಮೋಡ್ ಅನ್ನು ಆಯ್ಕೆ ಮಾಡಬಹುದು.\n\nಪೂರ್ವನಿಯೋಜಿತವಾಗಿ, ಸಾಮಾನ್ಯ ಮೋಡ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ ಏಕೆಂದರೆ ಇದು ಡೇಟಾವನ್ನು ಓದಲು ಮತ್ತು ಮಾರ್ಪಡಿಸಲು ಅನುಮತಿಯ ಅಗತ್ಯವಿಲ್ಲ. ನೀವು uBO Lite ಅನ್ನು ನಂಬುತ್ತಿದ್ದರೆ, ಡೀಫಾಲ್ಟ್ ಆಗಿ ಎಲ್ಲಾ ವೆಬ್‌ಸೈಟ್‌ಗಳಿಗೆ ಹೆಚ್ಚು ಸುಧಾರಿತ ಫಿಲ್ಟರಿಂಗ್ ಸಾಮರ್ಥ್ಯಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ಎಲ್ಲಾ ವೆಬ್‌ಸೈಟ್‌ಗಳಲ್ಲಿನ ಡೇಟಾವನ್ನು ಓದಲು ಮತ್ತು ಮಾರ್ಪಡಿಸಲು ನೀವು ವಿಶಾಲವಾದ ಅನುಮತಿಯನ್ನು ನೀಡಬಹುದು.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ko/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ko/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ko/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ko/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "설정", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "개발자용", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "정보", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "필터링 모드", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "이 사이트의 이슈를 신고하기", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "지역, 언어", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "변경 로그", "description": "" @@ -111,6 +131,10 @@ "message": "특정 웹사이트에서 발생하는 필터 이슈를 uBlockOrigin/uAssets 이슈 트래커에 신고할 수 있습니다. GitHub 계정이 필요합니다.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "문제 해결 정보", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { "message": "봉사자들이 중복 신고로 인해 부담을 겪지 않도록, 해당 이슈가 이미 신고되지는 않았는지 확인해주시기 바랍니다.", "description": "A paragraph in the filter issue reporter section" @@ -167,14 +191,6 @@ "message": "새 신고 생성", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "환영합니다", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "uBO Lite를 설치하셨습니다. 모든 웹사이트에 적용할 기본 필터링 모드를 선택해주세요.\n\n데이터를 읽고 변경하는 권한이 필요 없는 기본 모드가 기본 설정입니다. uBO Lite를 신뢰하신다면, 모든 웹사이트에서 데이터를 읽고 변경하는 권한을 부여해서 모든 웹사이트에 대해 고급 필터링 기능을 기본적으로 켤 수 있습니다.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "기본 필터링 모드", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "잠재적으로 좋지 않은 사이트로의 접속을 차단하고, 사용자가 진행할지 선택하도록 합니다.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "개발자 모드", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "기술적 사용자를 위한 기능에 접근할 수 있도록 합니다.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "목록 찾기", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "계속", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "구성 요소 제거 모드로 진입", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "구성 요소 제거 모드 종료", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "보기:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "필터링 모드 상세정보", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "사용자 지정 DNR 규칙", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR 규칙…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "동적 규칙 목록", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "세션 규칙 목록", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "저장", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "되돌리기", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "가져오기 및 추가하기…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "내보내기…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "신뢰할 수 없는 출처의 콘텐츠를 추가하지 마십시오", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "등록된 규칙 수: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/lt/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/lt/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/lt/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/lt/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "A permission-less content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", + "message": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Nustatymai", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Apie", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Report an issue", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Regionai, kalbos", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Pakeitimų žurnalas", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/lv/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/lv/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/lv/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/lv/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Iestatījumi", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Pielāgoti atsijātāji", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Izstrādāt", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Par", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "aizturēšanas veids", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Šajā tīmekļvietnē", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "Ziņot par nepilnību šajā tīmekļa vietnē", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "Apgabali, valodas", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Ievietot/izgūt", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Šeit ir ielīmējami noteikti kosmētiskie aizturētāji, kurus pievienot", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Izmaiņu žurnāls", "description": "" @@ -111,8 +131,12 @@ "message": "Ziņot par aizturēšanas filtru nepilnībām noteiktās vietnēs uBlockOrigin/uAssets pieteikumu izsekotājā. Nepieciešams GitHub konts.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Traucējummeklēšanas informācija", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Lai izvairītos no brīvprātīgo noslogošanas ar ziņojumiem, kas atkārtojas, lūgums pārbaudīt, ka par šādu nepilnību jau nav ziņots.", + "message": "Lai izvairītos no brīvprātīgo noslogošanas ar ziņojumiem, kas atkārtojas, lūgums pārbaudīt, ka par šādu nepilnību jau nav ziņots. Piebilde: klikšķināšana uz pogas izraisīs arī lapas izcelsmes nosūtīšanu uz GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { @@ -167,14 +191,6 @@ "message": "Izveidot jaunu ziņojumu", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Sveicināti!", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Tikko tika uzstādīts uBO Lite. Šeit var izvēlēties noklusējuma aizturēšanas veidu, ko izmantot visām tīmekļa vietnēm.\n\nPēc noklusējuma ir atlasīts Pamata, jo tam nav nepieciešama atļauja lasīt un mainīt datus. Ja uBO Lite šķiet uzticams, ir iespējams piešķirt plašas atļaujas lasīt un mainīt datus visās tīmekļa vietnēs, lai pēc noklusējuma iespējotu pilnīgākas aizturēšanas spējas visās tīmekļa vietnēs.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Noklusējuma aizturēšanas veids", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Iespējami nevēlamu vietņu apmeklēšana tiks aizturēta, un tiks piedāvāta iespēja turpināt.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Izstrādātāja režīms", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Iespējot piekļuvi iespējām, kas piemērotas tehniskiem lietotājiem.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Rezerves kopija", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Pielāgoto iestatījumu rezerves kopēšana datnē vai to atjaunošana no datnes.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Atjaunošana pārrakstīs visus pašreizējos pielāgotos iestatījumus.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Atrast sarakstus", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Turpināt", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Pārslēgties uz elementu iznīcināšanu", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Iziet no elementu iznīcināšanas", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Izveidot pielāgotu aizturētāju", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Noņemt pielāgotu aizturētāju", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Apskatīt", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Aizturēšanas režīma informācija", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Pielāgotas DNR kārtulas", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR kārtulas …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dinamiska kārtulu kopa", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Sesijas kārtulu kopa", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Saglabāt", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Atjaunot", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Pievienot", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Ievietot un pievienot…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Izgūt…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Veikt rezerves kopēšanu…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Atjaunot…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Nevajag pievienot saturu no neuzticamiem avotiem.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Reģistrēto kārtulu skaits: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Jābīda slīdnis, lai atlasītu vislabāko atbilstību", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Izvēlēties", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Priekšskatīt", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Izveidot", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Zemāk jāatlasa atlasītājs, lai tīmekļa lapā izceltu atbilstošos elementus. Klikšķināt uz atkritnes, lai noņemtu aizturētāju.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/mk/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/mk/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/mk/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/mk/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Прилагодби", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Информации за...", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "Начини на прочистување", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "Пријави проблем на оваа веб-страница", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "Региони, Јазици", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Промени", "description": "" @@ -111,6 +131,10 @@ "message": "Пријавете проблеми со филтерите за специфични веб-страници до uBlockOrigin/uAssets issue tracker. Потребен е GitHub профил.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { "message": "За да се избегне оптоварување на волонтерите со дупликат пријави, ве молиме проверете дали проблемот веќе не е пријавен.", "description": "A paragraph in the filter issue reporter section" @@ -167,14 +191,6 @@ "message": "Создај нова пријава", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Добредојде", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Токму ја инсталиравте uBO Lite. Овде можете да изберете режим на филтрирање по подразбирање што ќе го користите на сите веб-страници.\n\nПо подразбирање, е избран режимот Основен затоа што не бара дозвола за читање и модификација на податоци. Ако му верувате на uBO Lite, можете да му дадете ширување на дозволата за читање и модификација на податоци на сите веб-страници за да овозможите попрецизни способности за филтрирање на сите веб-страници по подразбирање.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Режим на филтрирање по подразбирање", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Најди листи", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ml/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ml/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ml/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ml/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "ക്രമീകരണങ്ങൾ", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "കുറിച്ച്", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "ഫിൽട്ടറിംഗ് മോഡ്", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Report an issue", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "പ്രാദേശികം, ഭാഷകള്‍", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "ചേഞ്ച് ലോഗ്", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "സ്വാഗതം", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "നിങ്ങൾ ഇപ്പോൾ uBO Lite ഇൻസ്റ്റാൾ ചെയ്തു. എല്ലാ വെബ്‌സൈറ്റുകളിലും ഉപയോഗിക്കുന്നതിന് ഇവിടെ നിങ്ങൾക്ക് ഡിഫോൾട്ട് ഫിൽട്ടറിംഗ് മോഡ് തിരഞ്ഞെടുക്കാം.\n\nസ്ഥിരസ്ഥിതിയായി, അടിസ്ഥാന മോഡ് തിരഞ്ഞെടുത്തു, കാരണം ഡാറ്റ വായിക്കാനും പരിഷ്ക്കരിക്കാനും അനുമതി ആവശ്യമില്ല. നിങ്ങൾ uBO Lite-നെ വിശ്വസിക്കുന്നുവെങ്കിൽ, ഡിഫോൾട്ടായി എല്ലാ വെബ്‌സൈറ്റുകൾക്കും കൂടുതൽ വിപുലമായ ഫിൽട്ടറിംഗ് കഴിവുകൾ പ്രാപ്‌തമാക്കുന്നതിന് എല്ലാ വെബ്‌സൈറ്റുകളിലെയും ഡാറ്റ വായിക്കാനും പരിഷ്‌ക്കരിക്കാനും നിങ്ങൾക്ക് വിശാലമായ അനുമതി നൽകാം.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "ഡിഫോൾട്ട് ഫിൽട്ടറിംഗ് മോഡ്", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/mr/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/mr/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/mr/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/mr/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "A permission-less content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", + "message": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Report an issue", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Regions, languages", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Changelog", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ms/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ms/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ms/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ms/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Tetapan", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Mengenai", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "mod penapisan", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Report an issue", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Wilayah, bahasa", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Log perubahan", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Selamat datang", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Anda baru sahaja memasang uBO Lite. Di sini anda boleh memilih mod penapisan lalai untuk digunakan pada semua tapak web.\n\nSecara lalai, mod Asas dipilih kerana ia tidak memerlukan kebenaran untuk membaca dan mengubah suai data. Jika anda mempercayai uBO Lite, anda boleh memberikannya kebenaran untuk membaca dan mengubah suai data pada semua tapak web untuk mendayakan keupayaan penapisan yang lebih maju untuk semua tapak web secara lalai.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Mod penapisan lalai", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/nb/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/nb/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/nb/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/nb/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Innstillinger", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Egendefinerte filtre", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Utvikle", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Om", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtreringsmodus", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "På denne nettsiden", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Rapporter et problem", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -60,7 +72,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Domener med skadelig programvare", + "message": "Beskyttelse mot skadelig programvare, sikkerhet", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -75,6 +87,14 @@ "message": "Regioner, språk", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Importér/Eksportér", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Lim inn her spesifikke kosmetiske filtre som skal legges til", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Endringslogg", "description": "" @@ -104,77 +124,73 @@ "description": "Shown in the About pane" }, "supportS6H": { - "message": "Report a filter issue", + "message": "Rapporter om filterproblem", "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS3P1": { - "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", + "message": "Rapporter filterproblemer med bestemte nettsteder til uBlockOrigin/uAssets problemsporing. Krever en GitHub-konto.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Feilsøkingsinformasjon", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "For å unngå å belaste de frivillige med dobbeltrapporter, må du kontrollere at problemet ikke allerede har blitt rapportert. Noter: ved å klikke på knappen vil sidens opprinnelse bli sendt til GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Finn lignende rapporter på GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { - "message": "Address of the webpage:", + "message": "Nettsidens adresse:", "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "The webpage…", + "message": "Nettsiden...", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { - "message": "-- Pick an entry --", + "message": "-- Velg en oppføring --", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { - "message": "Shows ads or ad leftovers", + "message": "Viser reklame eller reklamerester", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "Has overlays or other nuisances", + "message": "Har overlegg eller andre plager", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { - "message": "Detects uBO Lite", + "message": "Oppdager uBO Lite", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { - "message": "Has privacy-related issues", + "message": "Har personvernrelaterte problemer", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "Malfunctions when uBO Lite is enabled", + "message": "Fungerer ikke når uBO Lite er aktivert", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { - "message": "Opens unwanted tabs or windows", + "message": "Åpner uønskede faner eller vinduer", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { - "message": "Leads to badware, phishing", + "message": "Fører til skadelig programvare og/eller phishing", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { - "message": "Label the webpage as “NSFW” (“Not Safe For Work”)", + "message": "Merk nettsiden som «NSFW» (“Not Safe For Work”)", "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Opprett ny rapport på GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Velkommen", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Du har nettopp installert uBO Lite. Her kan du velge standard-filtreringsmodusen som skal brukes på alle nettsteder.\n\nSom standard er modusen Grunnleggende valgt fordi den ikke krever tillatelse til å lese og endre data. Hvis du stoler på uBO Lite, kan du gi uBO Lite bred tillatelse til å lese og endre data på alle nettsteder for å aktivere mer avanserte filtreringsfunksjoner for alle nettsteder som standard.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Standard filtreringsmodus", "description": "The header text for the default filtering mode section" @@ -212,11 +228,11 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Liste over vertsnavn der ingen filtrering vil finne sted", + "message": "Liste over nettsider der ingen filtrering vil finne sted.", "description": "A short description for the editable field which lists trusted sites" }, "noFilteringModePlaceholder": { - "message": "[hostnames only]\nexample.com\ngames.example\n...", + "message": "[kun vertsnavn]\nexample.com\ngames.example\n...", "description": "Default text for in edit field" }, "behaviorSectionLabel": { @@ -232,51 +248,167 @@ "description": "Label for a checkbox in the options page" }, "enableStrictBlockLabel": { - "message": "Enable strict blocking", + "message": "Aktiver streng blokkering", "description": "Label for a checkbox in the options page" }, "enableStrictBlockLegend": { - "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "message": "Navigering til potensielt uønskede nettsteder blir blokkert, og du får tilbud om å fortsette.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Utviklermodus", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Aktiver tilgang til funksjoner som er egnet for tekniske brukere.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Sikkerhetskopi", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Sikkerhetskopier dine egendefinerte regler, eller gjenopprett dine egendefinerte regler fra en fil.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Gjenoppretting vil overskrive dine nåværende egendefinerte regler.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { - "message": "Find lists", + "message": "Finn lister", "description": "Placeholder for the input field used to find lists" }, "strictblockTitle": { - "message": "Page blocked", + "message": "Side blokkert", "description": "Webpage title for the strict-blocked page" }, "strictblockSentence1": { - "message": "uBO Lite has prevented the following page from loading:", + "message": "uBO Lite har forhindret innlasting av følgende side:", "description": "Sentence used in the strict-blocked page" }, "strictblockReasonSentence1": { - "message": "The page was blocked because of a matching filter in {{listname}}.", + "message": "Siden ble blokkert på grunn av et matchende filter i {{listname}}.", "description": "Text informing about what is causing the page to be blocked" }, "strictblockRedirectSentence1": { - "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", + "message": "Den blokkerte siden ønsker å omdirigere til et annet nettsted. Hvis du velger å fortsette, vil du navigere direkte til: {{url}}", "description": "Text warning about an incoming redirect" }, "strictblockNoParamsPrompt": { - "message": "without parameters", + "message": "uten parametere", "description": "Label to be used for the parameter-less URL" }, "strictblockBack": { - "message": "Go back", + "message": "Gå tilbake", "description": "A button to go back to the previous webpage" }, "strictblockClose": { - "message": "Close this window", + "message": "Lukk dette vinduet", "description": "A button to close the current tab" }, "strictblockDontWarn": { - "message": "Don't warn me again about this site", + "message": "Ikke varsle igjen om dette nettstedet", "description": "Label for checkbox in document-blocked page" }, "strictblockProceed": { - "message": "Proceed", + "message": "Fortsett", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Gå til element­fjernings­modus", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Forlat elementfjerningsmodus", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Lag et egendefinert filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Fjern et egendefinert filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Vis:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtreringsmodusdetaljer", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Egendefinerte DNR-regler", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR-regler for …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamisk regelsett", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Regelsett for økter", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Lagre", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Tilbakestill", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Legg til", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Importer og legg til...", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Eksporter...", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Sikkerhetskopier…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Gjenopprett…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Ikke legg til innhold fra upålitelige kilder", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Antall registrerte regler: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Flytt glidebryteren for å velge den beste matchen", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Velg", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Forhåndsvis", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Opprett", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Velg et filter nedenfor for å fremheve samsvarende elementer på nettsiden. Klikk på papirkurven for å fjerne et filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/nl/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/nl/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/nl/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/nl/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Een toestemmingsloze inhoudsblokkeerder. Blokkeert direct na installatie advertenties, trackers, miners en meer.", + "message": "Een efficiënte inhoudsblokkeerder. Blokkeert direct na installatie advertenties, trackers, miners en meer.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Instellingen", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Aangepaste filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Ontwikkelen", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Over", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtermodus", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Op deze website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Een probleem op deze website melden", + "message": "Een probleem melden", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -60,7 +72,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malwaredomeinen", + "message": "Bescherming tegen malware, beveiliging", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -75,6 +87,14 @@ "message": "Gebieden, talen", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Importeren / Exporteren", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Plak hier specifieke cosmetische filters om toe te voegen", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Wijzigingenlogboek", "description": "" @@ -111,12 +131,16 @@ "message": "Meld filterproblemen met specifieke websites in de uBlockOrigin/uAssets-probleemtracker. Vereist een GitHub-account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Probleemoplossingsinformatie", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Controleer of het probleem niet eerder is gemeld om te voorkomen dat vrijwilligers met dubbele meldingen worden belast.", + "message": "Controleer of het probleem niet eerder is gemeld om te voorkomen dat vrijwilligers met dubbele meldingen worden belast. Noot: op de knop klikken zorgt ervoor dat de oorsprong van de pagina naar GitHub wordt verzonden.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Soortgelijke meldingen zoeken", + "message": "Soortgelijke meldingen op GitHub zoeken", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Nieuwe melding maken", + "message": "Nieuwe melding op GitHub maken", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Welkom", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "U hebt zojuist uBO Lite geïnstalleerd. Hier kunt u de standaard filtermodus voor het gebruik op alle websites kiezen.\n\nStandaard wordt de modus Basis geselecteerd, omdat hiervoor geen toestemming voor het lezen en aanpassen van gegevens is vereist. Als u uBO Lite vertrouwt, kunt u het brede toestemming voor het lezen en aanpassen van gegevens op alle websites verlenen, zodat standaard meer geavanceerde filtermogelijkheden voor alle websites beschikbaar zijn.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Standaard filtermodus", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigatie naar mogelijk ongewenste websites wordt geblokkeerd, en u krijgt de mogelijkheid om door te gaan.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Ontwikkelaarsmodus", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Schakelt toegang tot voor technische gebruikers geschikte functies in.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Back-up", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Maak een back-up van uw aangepaste instellingen naar een bestand, of zet uw aangepaste instellingen terug vanuit een bestand.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Terugzetten overschrijft al uw huidige aangepaste instellingen.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Lijsten zoeken", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Doorgaan", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Een element­ verwijderen", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Element­wisser­modus sluiten", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Een aangepast filter maken", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Een aangepast filter verwijderen", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Weergeven:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Details van filtermodus", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Aangepaste DNR-regels", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR-regels van …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamische regelset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Sessieregelset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Opslaan", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Ongedaan maken", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Toevoegen", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Importeren en toevoegen…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exporteren…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back-up maken…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Terugzetten…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Voeg geen inhoud van niet-vertrouwde bronnen toe.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Aantal geregistreerde regels: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Verplaats de schuifregelaar voor de beste overeenkomst", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Kiezen", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Voorbeeld", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Aanmaken", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Selecteer hieronder een filter om overeenkomende elementen in de webpagina te markeren. Klik op de prullenbak om een filter te verwijderen.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/oc/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/oc/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/oc/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/oc/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "A permission-less content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", + "message": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Report an issue", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Regions, languages", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Changelog", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/pa/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/pa/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/pa/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/pa/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "ਸੈਟਿੰਗਾਂ", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "ਇਸ ਬਾਰੇ", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "ਫਿਲਟਰ ਕਰਨ ਦਾ ਮੋਡ", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "ਇਸ ਵੈੱਬਸਾਈਟ ਉੱਤੇ ਮਸਲੇ ਬਾਰੇ ਰਿਪੋਰਟ ਕਰੋ", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "ਖੇਤਰ, ਭਾਸ਼ਾਵਾਂ", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "ਤਬਦੀਲੀ-ਸੂਚੀ", "description": "" @@ -111,8 +131,12 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { @@ -167,14 +191,6 @@ "message": "ਨਵੀਂ ਰਿਪੋਰਟ ਬਣਾਓ", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "ਜੀ ਆਇਆਂ ਨੂੰ", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "ਤੁਸੀਂ ਹੁਣੇ ਹੀ uBO Lite ਨੂੰ ਇੰਸਟਾਲ ਕੀਤਾ ਹੈ। ਤੁਸੀਂ ਸਾਰੀਆਂ ਵੈੱਬਸਾਈਟਾਂ ਲਈ ਵਰਤਣ ਵਾਸਤੇ ਮੂਲ ਫਿਲਟਰ ਕਰਨ ਦੇ ਢੰਗ ਨੂੰ ਚੁਣ ਸਕਦੇ ਹੋ।\n\nਮੂਲ ਰੂਪ ਵਿੱਚ ਮੁੱਢਲਾ (Basic) ਢੰਗ ਚੁਣਿਆ ਜਾਂਦਾ ਹੈ, ਕਿਉਂਕਿ ਇਸ ਵਾਸਤੇ ਡਾਟਾ ਪੜ੍ਹਨ ਅਤੇ ਸੋਧਣ ਲਈ ਕਿਸੇ ਵੀ ਮਨਜ਼ੂਰੀ ਦੀ ਲੋੜ ਨਹੀਂ ਹੁੰਦੀ ਹੈ। ਜੇ ਤੁਹਾਨੂੰ uBO Lite ਉੱਤੇ ਭਰੋਸਾ ਹੋਵੇ ਤਾਂ ਤੁਸੀਂ ਇਸ ਨੂੰ ਸਾਰੀਆਂ ਵੈੱਬਸਾਈਟਾਂ ਉੱਤੇ ਮੂਲ ਰੂਪ ਵਿੱਚ ਹੀ ਵੱਧ ਤਕਨੀਕੀ ਫਿਲਟਰ ਸਮਰੱਥਾ ਨੂੰ ਚਾਲੂ ਕਰਨ ਲਈ ਸਭ ਵੈੱਬਸਾਈਟਾਂ ਉੱਤੇ ਡਾਟਾ ਪੜ੍ਹਨ ਅਤੇ ਸੋਧਣ ਲਈ ਜਿਆਦਾ ਮਨਜ਼ੂਰੀ ਦੇ ਸਕਦੇ ਹੋ।", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "ਮੂਲ ਫਿਲਟਰ ਕਰਨ ਦਾ ਢੰਗ", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/pl/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/pl/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/pl/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/pl/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Ustawienia", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Własne filtry", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Programowanie", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "O rozszerzeniu", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "Tryb filtrowania", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Na tej stronie internetowej", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "Zgłoś problem z tą stroną", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "Regiony, języki", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import i eksport", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Wklej tutaj określone filtry kosmetyczne do dodania", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Informacje o wydaniu", "description": "" @@ -111,8 +131,12 @@ "message": "Zgłoś problemy z filtrami dotyczące konkretnych witryn internetowych do systemu śledzenia problemów uBlockOrigin/uAssets. Wymagane jest konto GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Informacje pomocne w rozwiązywaniu problemów", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Aby uniknąć obciążania wolontariuszy zduplikowanymi zgłoszeniami, sprawdź, czy problem nie został już zgłoszony.", + "message": "Sprawdź, czy problem nie został już zgłoszony, aby uniknąć obciążania wolontariuszy duplikatami raportów. Uwaga: kliknięcie przycisku spowoduje wysłanie źródła strony do serwisu GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { @@ -167,14 +191,6 @@ "message": "Utwórz nowy raport", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Witaj", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Właśnie został zainstalowany uBO Lite. Tutaj możesz wybrać domyślny tryb filtrowania, który będzie używany na wszystkich witrynach internetowych.\n\nDomyślnie wybrany jest tryb Podstawowy, ponieważ nie wymaga uprawnień do odczytu i zmiany danych. Jeśli ufasz uBO Lite, możesz nadać mu szerokie uprawnienia do odczytu i zmiany danych na wszystkich witrynach internetowych w celu domyślnego włączenia bardziej zaawansowanych funkcji filtrowania wszystkich witryn internetowych.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Domyślny tryb filtrowania", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Nawigacja do potencjalnie niepożądanych witryn zostanie zablokowana i pojawi się opcja kontynuowania.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Tryb programisty", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Włącz dostęp do odpowiednich funkcji dla użytkowników technicznych.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Tworzenie i przywracanie kopii zapasowej", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Utwórz kopię zapasową własnych ustawień w pliku lub przywróć je z pliku.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Przywrócenie kopii zapasowej spowoduje nadpisanie wszystkich bieżących ustawień własnych.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Znajdź listy", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Kontynuuj", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Przejdź do trybu usuwania elementów", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Wyjdź z trybu usuwania elementów", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Utwórz własny filtr", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Usuń własny filtr", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Widok:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Szczegóły trybu filtrowania", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Własne reguły DNR", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Reguły DNR …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamiczny zestaw reguł", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Sesyjny zestaw reguł", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Zapisz", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Przywróć", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Dodaj", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Importuj i dołącz…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Eksportuj…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Utwórz kopię zapasową…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Przywróć kopię zapasową…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Nie dodawaj zawartości z niezaufanych źródeł", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Liczba zarejestrowanych reguł: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Przesuń suwak, aby wybrać najlepsze dopasowanie", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Wybierz", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Podgląd", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Utwórz", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Wybierz filtr poniżej, aby wyróżnić pasujące elementy na stronie internetowej. Kliknij kosz, aby usunąć filtr.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/pt_BR/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/pt_BR/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/pt_BR/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/pt_BR/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Um bloqueador de conteúdo com menos permissões — Bloqueie anúncios, rastreadores, mineradores e mais imediatamente após a instalação", + "message": "Um bloqueador de conteúdo eficiente. Bloqueia anúncios, rastreadores e muito mais, imediatamente após a instalação.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Configurações", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Filtros personalizados", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Desenvolver", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Sobre", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "modo de filtragem", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Neste site", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Reportar um problema neste site da web", + "message": "Reportar um problema", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -60,7 +72,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Domínios de malware", + "message": "Proteção contra malware, segurança", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -68,15 +80,23 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMisc": { - "message": "Miscelãnea", + "message": "Outras", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupRegions": { "message": "Regiões, idiomas", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Importação e exportação", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Cole filtros cosméticos específicos aqui para adicioná-los", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { - "message": "Changelog", + "message": "Notas de lançamento", "description": "" }, "aboutCode": { @@ -88,7 +108,7 @@ "description": "English: Contributors" }, "aboutSourceCode": { - "message": "Código fonte", + "message": "Código-fonte", "description": "Link text to source code repo" }, "aboutTranslations": { @@ -108,35 +128,39 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS3P1": { - "message": "Reporte problemas dos filtros com sites da web específicos no rastreador de problemas uBlockOrigin/uAssets. Requer uma conta no GitHub.", + "message": "Reporte problemas com os filtros em sites específicos no rastreador de problemas douBlockOrigin/uAssets. Uma conta do GitHub é necessária.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Informações para solução de problemas", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Pra evitar sobrecarregar os voluntários com relatórios duplicados por favor verifique se o problema já não foi reportado.", + "message": "Para evitar sobrecarregar os voluntários com relatórios duplicados por favor verifique se o problema já não foi relatado. Observação: clicar no botão fará com que a origem da página seja enviada ao GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Achar relatórios similares", + "message": "Procurar relatórios similares no GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { - "message": "Endereço da página da web:", + "message": "Endereço da página:", "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "A página da web…", + "message": "A página…", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { - "message": "— Escolha uma entrada —", + "message": "— Selecione um tipo —", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { - "message": "Mostra os anúncios ou restos de anúncios", + "message": "Mostra anúncios ou restos de anúncios", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "Tem sobreposições ou outros incômodos", + "message": "Tem sobreposições ou outras perturbações", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { @@ -144,11 +168,11 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { - "message": "Tem problemas relacionados a privacidade", + "message": "Tem problemas relacionados à privacidade", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "Funciona mal quando o uBO Lite está ativado", + "message": "Não funciona direito quando o uBO Lite está ativado", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { @@ -160,27 +184,19 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { - "message": "Rotular a página da web como “NSFW” (“Not Safe For Work”)", + "message": "Rotular a página como “NSFW” (“Not Safe For Work”)", "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Criar novo relatório", + "message": "Criar um novo relatório no GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Bem-vindo", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Você instalou o uBO Lite. Aqui você pode escolher o modo de filtragem padrão pra usar em todos os sites da web.\n\nPor padrão o modo Básico está selecionado porque não requer permissão pra ler e modificar os dados. Se você confia no uBO Lite você pode dar ampla permissão pra ler e modificar os dados em todos os sites da web de modo a ativar as capacidades de filtragem mais avançadas pra todos os sites da web por padrão.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Modo de filtragem padrão", "description": "The header text for the default filtering mode section" }, "defaultFilteringModeDescription": { - "message": "O modo de filtragem padrão será substituído pelos modos de filtragem por site. Você pode ajustar o modo de filtragem em qualquer site dado da web de acordo com qualquer modo que funcionar melhor nesse site da web. Cada modo tem suas vantagens e desvantagens.", + "message": "O modo de filtragem padrão será substituído pelos modos de filtragem por site. Você pode ajustar o modo de filtragem em qualquer site de acordo com qual modo funcionar melhor nesse site. Cada modo tem suas vantagens e desvantagens.", "description": "This describes the default filtering mode setting" }, "filteringMode0Name": { @@ -200,23 +216,23 @@ "description": "Name of blocking mode 3" }, "basicFilteringModeDescription": { - "message": "Filtragem básica da rede de listas de filtros selecionadas.\n\nNão requer permissão pra ler e modificar os dados nos sites da web.", + "message": "Filtragem básica de rede por listas de filtros selecionadas.\n\nNão requer permissão para ler e modificar os dados nos sites.", "description": "This describes the 'basic' filtering mode" }, "optimalFilteringModeDescription": { - "message": "Filtragem avançada da rede mais filtragem estendida específica das listas de filtros selecionadas.\n\nRequer ampla permissão pra ler e modificar os dados em todos os sites da web.", + "message": "Filtragem avançada de rede, com a filtragem estendida específica de listas de filtros selecionadas.\n\nRequer a permissão mais extensa de ler e modificar os dados em todos os sites.", "description": "This describes the 'optimal' filtering mode" }, "completeFilteringModeDescription": { - "message": "Filtragem avançada da rede mais filtragem estendida específica e genérica das listas de filtros selecionadas.\n\nRequer ampla permissão pra ler e modificar os dados em todos os sites da web.\n\nA filtragem estendida genérica pode causar maior uso de recursos da página da web.", + "message": "Filtragem avançada da rede, com filtragem estendida específica e genérica de listas de filtros selecionadas.\n\nRequer a permissão mais extensa para ler e modificar os dados em todos os sites.\n\nA filtragem estendida genérica pode causar maior uso de recursos da página.", "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Lista de nomes dos hospedeiros para os quais nenhuma filtragem acontecerá.", + "message": "Lista de sites que não serão filtrados.", "description": "A short description for the editable field which lists trusted sites" }, "noFilteringModePlaceholder": { - "message": "[só nomes de hospedeiros]\nexemplo.com\njogos.exemplo", + "message": "[somente nomes de servidor]\nexemplo.com\njogos.exemplo\n...", "description": "Default text for in edit field" }, "behaviorSectionLabel": { @@ -224,11 +240,11 @@ "description": "The header text for the 'Behavior' section" }, "autoReloadLabel": { - "message": "Recarregar a página automaticamente quando mudar o modo de filtragem", + "message": "Recarregar a página automaticamente ao alterar o modo de filtragem", "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { - "message": "Mostrar o número de requisições bloqueadas no ícone da barra de ferramentas", + "message": "Mostrar o número de solicitações bloqueadas no ícone da barra de ferramentas", "description": "Label for a checkbox in the options page" }, "enableStrictBlockLabel": { @@ -236,11 +252,31 @@ "description": "Label for a checkbox in the options page" }, "enableStrictBlockLegend": { - "message": "A navegação até sites potencialmente indesejáveis ​​será bloqueada e será oferecido a você a opção de prosseguir.", + "message": "A navegação para sites potencialmente indesejáveis ​​será bloqueada e você terá a opção de prosseguir.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Modo de desenvolvedor", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Ativa o acesso à funcionalidade destinada a usuários técnicos.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Faça backup das suas configurações personalizadas em um arquivo ou restaure suas configurações personalizadas de um arquivo.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "A restauração sobrescreverá todas as suas configurações personalizadas atuais.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { - "message": "Achar listas", + "message": "Procurar listas", "description": "Placeholder for the input field used to find lists" }, "strictblockTitle": { @@ -252,7 +288,7 @@ "description": "Sentence used in the strict-blocked page" }, "strictblockReasonSentence1": { - "message": "A página foi bloqueada por causa de um filtro que combina no {{listname}}.", + "message": "A página foi bloqueada devido a um filtro correspondente em {{listname}}.", "description": "Text informing about what is causing the page to be blocked" }, "strictblockRedirectSentence1": { @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Prosseguir", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remover um elemento", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Sair do modo de remoção de elementos", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Criar um filtro personalizado", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remover um filtro personalizado", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Visualizar:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Detalhes do modo de filtragem", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Regras DNR personalizadas", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Regras DNR de…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Conjunto de regras dinâmicas", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Conjunto de regras da sessão", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Salvar", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Reverter", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Adicionar", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Importar e anexar…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exportar…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Fazer backup…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restaurar…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Não adicione conteúdo de fontes não confiáveis.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Número de regras registradas: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Mova o controle para selecionar a melhor correspondência", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Selecionar", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Pré-visualizar", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Criar", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Selecione um filtro abaixo para destacar os elementos correspondentes na página. Clique na lixeira para remover um filtro.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/pt_PT/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/pt_PT/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/pt_PT/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/pt_PT/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Um bloqueador de conteúdo sem permissões. Bloqueia anúncios, rastreadores e muito mais, imediatamente após a instalação.", + "message": "Um bloqueador de conteúdo eficiente. Bloqueia anúncios, rastreadores, mineradores e muito mais imediatamente após a instalação.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Definições", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Filtros personalizados", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Programação", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Acerca", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "modo de filtragem", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Neste website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Relatar um problema neste website", + "message": "Relatar um problema", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -60,7 +72,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Domínios maliciosos", + "message": "Proteção contra malware, segurança", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -75,6 +87,14 @@ "message": "Regiões, idiomas", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Importar / Exportar", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Cole aqui filtros cosméticos específicos a adicionar", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Registo de alterações", "description": "" @@ -111,12 +131,16 @@ "message": "Relate problemas de filtros em websites específicos no controlador de problemas uBlockOrigin/uAssets. Requer uma conta GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Informação sobre resolução de problemas", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Para evitar sobrecarregar os voluntários com relatórios duplicados, verifique se o problema ainda não foi relatado.", + "message": "Para evitar sobrecarregar os voluntários com relatórios duplicados, verifique se o problema ainda não foi relatado. Nota: clicar no botão fará com que a origem da página seja enviada para o GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Encontrar relatórios semelhantes", + "message": "Encontrar relatórios semelhantes no GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -160,21 +184,13 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { - "message": "Classifica a página web como “NSFW” (“Não segura para o trabalho”)", + "message": "Classificar a página web como “NSFW” (“Não segura para o trabalho”)", "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Criar novo relatório", + "message": "Criar novo relatório no GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Bem-vindo(a)", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Acabou de instalar o uBO Lite. Pode escolher aqui o modo de filtragem predefinido para usar em todos os websites.\n\nPor predefinição, o modo Básico é selecionado porque não requer a permissão para ler e modificar dados. Se confiar no uBO Lite, pode dar-lhe ampla permissão para ler e modificar dados em todos os websites, a fim de ativar capacidades de filtragem mais avançadas para todos os websites por predefinição.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Modo de filtragem predefinido", "description": "The header text for the default filtering mode section" @@ -212,7 +228,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Lista de nomes de websites para os quais não será efetuada qualquer filtragem.", + "message": "Lista de websites para os quais não será efetuada qualquer filtragem.", "description": "A short description for the editable field which lists trusted sites" }, "noFilteringModePlaceholder": { @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "A navegação para sites potencialmente indesejáveis será bloqueada e ser-lhe-á dada a opção de proceder.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Modo de programador", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Permite acesso a funcionalidades adequadas a utilizadores técnicos", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Cópia de segurança", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Faça uma cópia de segurança das suas definições personalizadas num ficheiro ou restaure as suas definições personalizadas a partir de um ficheiro.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "A restauração substituirá todas as suas definições personalizadas atuais.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Encontrar listas", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceder", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remover um elemento", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Sair do modo de remoção rápida de elemento", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Criar um filtro personalizado", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remover um filtro personalizado", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Ver:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Detalhes do modo de filtragem", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Regras DNR personalizadas", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Regras DNR de…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Conjunto de regras dinâmico", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Conjunto de regras da sessão", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Guardar", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Reverter", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Adicionar", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Importar e anexar…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exportar…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Criar cópia…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restaurar…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Não adicione conteúdo de fontes não fidedignas", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Número de regras registadas: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Mova o controlo de deslize para selecionar a melhor correspondência", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Escolher", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Pré-visualizar", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Criar", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Selecione um filtro abaixo para destacar os elementos correspondentes na página web. Clique no caixote do lixo para remover um filtro.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ro/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ro/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ro/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ro/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Opțiuni", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Despre", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "Mod de filtrare", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Raportează o eroare pe acest site web", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Regiuni, limbi", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Jurnal de modificări", "description": "" @@ -104,77 +124,73 @@ "description": "Shown in the About pane" }, "supportS6H": { - "message": "Report a filter issue", + "message": "Raportează o problemă cu filtrele", "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS3P1": { - "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", + "message": "Raportează aici o eroare cu filtrele pentru un site specific uBlockOrigin/uAssets issue tracker. Este necesar un cont GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "Pentru a evita încărcarea voluntarilor cu rapoarte duplicate, vă rugăm să verificați dacă problema nu a fost deja raportată.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Găsiți rapoarte similare", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { - "message": "Address of the webpage:", + "message": "Adresa paginii web:", "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "The webpage…", + "message": "Pagina web…", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { - "message": "-- Pick an entry --", + "message": "-- Alege o intrare --", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { - "message": "Shows ads or ad leftovers", + "message": "Arată reclame sau resturi de reclame", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "Has overlays or other nuisances", + "message": "Are suprapuneri sau alte inconveniente", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { - "message": "Detects uBO Lite", + "message": "Detectează uBO Lite", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { - "message": "Has privacy-related issues", + "message": "Are probleme privind confidențialitatea", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "Malfunctions when uBO Lite is enabled", + "message": "Defecțiuni atunci când uBO Lite este activat", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { - "message": "Opens unwanted tabs or windows", + "message": "Deschide file sau ferestre nedorite", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { - "message": "Leads to badware, phishing", + "message": "Duce la programe dăunătoare, phishing", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { - "message": "Label the webpage as “NSFW” (“Not Safe For Work”)", + "message": "Etichetați pagina web ca “NSFW” (“Nu este sigur la locul de muncă”)", "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Creează o nouă sesizare", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Bun venit", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Tocmai ați instalat uBO Lite. Aici puteți alege modul de filtrare implicit pe toate site-urile.\n\nImplicit, modul de bază este selectat întrucât nu necesită permisiuni pentru a citi și modifica date. Dacă aveți încredere în uBO Lite, puteți să-i acordați permisiuni sporite pentru a citi și modifica datele tututor sitte-rilor pentru a activa capabilități mai avansate de filtrare.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Mod de filtrare implicit", "description": "The header text for the default filtering mode section" @@ -216,7 +232,7 @@ "description": "A short description for the editable field which lists trusted sites" }, "noFilteringModePlaceholder": { - "message": "[hostnames only]\nexample.com\ngames.example\n...", + "message": "[doar hostnames]\nexample.com\ngames.example\n...", "description": "Default text for in edit field" }, "behaviorSectionLabel": { @@ -232,51 +248,167 @@ "description": "Label for a checkbox in the options page" }, "enableStrictBlockLabel": { - "message": "Enable strict blocking", + "message": "Activați blocarea strictă", "description": "Label for a checkbox in the options page" }, "enableStrictBlockLegend": { - "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "message": "Navigarea către site-uri potențial nedorite va fi blocată și vi se va oferi opțiunea de a continua.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { - "message": "Find lists", + "message": "Căutați liste", "description": "Placeholder for the input field used to find lists" }, "strictblockTitle": { - "message": "Page blocked", + "message": "Pagină blocată", "description": "Webpage title for the strict-blocked page" }, "strictblockSentence1": { - "message": "uBO Lite has prevented the following page from loading:", + "message": "uBO Lite a împiedicat încărcarea următoarei pagini:", "description": "Sentence used in the strict-blocked page" }, "strictblockReasonSentence1": { - "message": "The page was blocked because of a matching filter in {{listname}}.", + "message": "Pagina a fost blocată din cauza unui filtru din {{listname}}.", "description": "Text informing about what is causing the page to be blocked" }, "strictblockRedirectSentence1": { - "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", + "message": "Pagina blocată dorește să redirecționeze către un alt site. Dacă alegeți să continuați, veți naviga direct către: {{url}}", "description": "Text warning about an incoming redirect" }, "strictblockNoParamsPrompt": { - "message": "without parameters", + "message": "fără parametri", "description": "Label to be used for the parameter-less URL" }, "strictblockBack": { - "message": "Go back", + "message": "Înapoi", "description": "A button to go back to the previous webpage" }, "strictblockClose": { - "message": "Close this window", + "message": "Închide fereastra", "description": "A button to close the current tab" }, "strictblockDontWarn": { - "message": "Don't warn me again about this site", + "message": "Nu mă avertiza din nou despre acest site", "description": "Label for checkbox in document-blocked page" }, "strictblockProceed": { - "message": "Proceed", + "message": "Continuă", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Alege un filtru de mai jos pentru a evidenția elementele cu potriviri în pagina web. Clic pe [Coș de gunoi] pentru a îndepărta un filtru.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ru/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ru/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ru/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ru/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Блокировщик контента, не требующий разрешений. Сразу после инсталляции блокирует рекламу, трекеры, майнеры и многое другое.", + "message": "Эффективный блокировщик веб-элементов. Сразу после установки блокирует рекламу, трекеры, майнеры и многое другое.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Настройки", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Пользовательские фильтры", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Разработка", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "О расширении", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "режим фильтрации", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "На этом сайте", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Сообщить о проблеме на этом сайте", + "message": "Сообщить о проблеме", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -60,7 +72,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Вредоносные домены", + "message": "Защита от вредоносных сайтов, безопасность", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -75,6 +87,14 @@ "message": "Регионы, языки", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Импорт / Экспорт", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Вставьте сюда отдельные косметические фильтры для добавления", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Список изменений", "description": "" @@ -111,12 +131,16 @@ "message": "Сообщайте о проблемах с фильтрами на определённых сайтах в трекер ошибок uBlockOrigin/uAssets. Требуется учётная запись в GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Диагностическая информация", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Чтобы не обременять волонтеров повторяющимися отчетами, пожалуйста, убедитесь, что о данной проблеме еще не сообщали.", + "message": "Чтобы не обременять добровольцев повторяющимися отчётами, пожалуйста, убедитесь, что об этой проблеме ещё не сообщали. Примечание: щелчок по кнопке приведёт к отправке адреса посещенной страницы GitHub'у.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Найти похожие отчеты", + "message": "Найти похожие отчёты в GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Создать новый отчет", + "message": "Создать новый отчёт в GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Добро пожаловать", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Вы только что установили uBO Lite. Здесь вы можете выбрать стандартный режим фильтрации для всех веб-сайтов.\n\nПо умолчанию выбран режим Базовый, так как он не требует разрешения на чтение и изменение данных. Если вы доверяете uBO Lite, вы можете дать ему широкие права на чтение и изменение данных на всех веб-сайтах, чтобы включить более продвинутые возможности фильтрации для всех веб-сайтов по умолчанию.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Режим фильтрации по умолчанию", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Переход к потенциально нежелательным сайтам будет заблокирован, и будет дана возможность продолжить переход на сайт", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Режим разработчика", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Включает доступ к функциям, предназначенным для технических пользователей.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Резервная копия", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Создайте резервную копию пользовательских настроек в файле, или восстановите настройки из файла.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Восстановление перезапишет все ваши текущие пользовательские настройки.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Найти списки", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Продолжить", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Убрать элемент", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Покинуть режим временного скрытия элемента", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Создать свой фильтр", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Удалить свой фильтр", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Просмотр:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Подробности режима фильтрации", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Пользовательские правила DNR", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Правила DNR для…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Динамический набор правил", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Набор правил для сессии", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Сохранить", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Вернуть", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Добавить", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Импортировать и добавить…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Экспортировать…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Создать рез. копию…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Восстановить…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Не добавлять содержимое из ненадёжных источников", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Число зарегистрированных правил: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Перемещайте ползунок для выбора лучшего варианта", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Выбрать элемент", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Предпросмотр", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Создать", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Выберите фильтр ниже, чтобы подсветить соответствующие элементы на странице. Нажмите на корзину для удаления фильтра.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/si/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/si/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/si/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/si/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "සැකසුම්", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "පිළිබඳ", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "පෙරීමේ ප්‍රකාරය", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "මෙම අඩවියේ ගැටලුවක් වාර්තා කරන්න", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "කලාපීය, භාෂා", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "වෙනස්කම් සටහන", "description": "" @@ -108,11 +128,15 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS3P1": { - "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", + "message": "නිශ්චිත වෙබ් අඩවි සමඟ පෙරහන් ගැටළු uBlockOrigin/uAssets ගැටළු ට්රැකර්වෙත වාර්තා කරන්න. GitHub ගිණුමක් අවශ්‍යයි.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "දෝශ නිරාකරණ තොරතුරු", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "අනුපිටපත් වාර්තා සමඟ ස්වේච්ඡා සේවකයින්ට බරක් වීම වළක්වා ගැනීම සඳහා, කරුණාකර ගැටළුව දැනටමත් වාර්තා කර නොමැති බව තහවුරු කරගන්න. සටහන: බොත්තම ක්ලික් කිරීමෙන් පිටුවේ මූලාරම්භය GitHub වෙත යවනු ලැබේ.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { @@ -132,11 +156,11 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { - "message": "Shows ads or ad leftovers", + "message": "දැන්වීම් හෝ දැන්වීම් ඉතිරි කොටස් පෙන්වයි", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "Has overlays or other nuisances", + "message": "උඩැතිරි හෝ වෙනත් කරදර ඇති", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { @@ -144,11 +168,11 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { - "message": "Has privacy-related issues", + "message": "පෞද්ගලිකත්‍වය ආශ්‍රිත ගැටළු තිබේ", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "Malfunctions when uBO Lite is enabled", + "message": "uBO Lite සක්‍රීය කර ඇති විට සිදුවන අක්‍රමිකතා", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { @@ -156,31 +180,23 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { - "message": "Leads to badware, phishing", + "message": "නරක මෘදුකාංග, තතුබෑම් වලට මග පාදයි", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { - "message": "Label the webpage as “NSFW” (“Not Safe For Work”)", + "message": "වෙබ් පිටුව “NSFW” ලෙස ලේබල් කරන්න (“වැඩ සඳහා ආරක්ෂිත නොවේ”)", "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { "message": "නව වාර්තාවක් සාදන්න", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "සාදරයෙන් පිළිගනිමු", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "පෙරනිමි පෙරීමේ ප්‍රකාරය", "description": "The header text for the default filtering mode section" }, "defaultFilteringModeDescription": { - "message": "The default filtering mode will be overridden by per-website filtering modes. You can adjust the filtering mode on any given website according to whichever mode works best on that website. Each mode has its advantages and disadvantages.", + "message": "පෙරනිමි පෙරහන් මාදිලිය එක් එක් වෙබ් අඩවියට පෙරහන් මාදිලි මගින් අභිබවා යනු ඇත. ඔබට ඕනෑම වෙබ් අඩවියක පෙරහන් මාදිලිය එම වෙබ් අඩවියේ වඩාත් හොඳින් ක්‍රියාත්මක වන මාදිලිය අනුව සකස් කළ හැකිය. සෑම මාදිලියකටම එහි වාසි සහ අවාසි ඇත.", "description": "This describes the default filtering mode setting" }, "filteringMode0Name": { @@ -200,15 +216,15 @@ "description": "Name of blocking mode 3" }, "basicFilteringModeDescription": { - "message": "Basic network filtering from selected filter lists.\n\nDoes not require permission to read and modify data on websites.", + "message": "තෝරාගත් පෙරහන් ලැයිස්තු වලින් මූලික ජාල පෙරහන.\n\nවෙබ් අඩවි වල දත්ත කියවීමට සහ වෙනස් කිරීමට අවසර අවශ්‍ය නොවේ.", "description": "This describes the 'basic' filtering mode" }, "optimalFilteringModeDescription": { - "message": "Advanced network filtering plus specific extended filtering from selected filter lists.\n\nRequires broad permission to read and modify data on all websites.", + "message": "තෝරාගත් පෙරහන් ලැයිස්තු වලින් උසස් ජාල පෙරහන් සහ නිශ්චිත දිගු පෙරහන්.\n\nසියලුම වෙබ් අඩවි වල දත්ත කියවීමට සහ වෙනස් කිරීමට පුළුල් අවසරයක් අවශ්‍ය වේ.", "description": "This describes the 'optimal' filtering mode" }, "completeFilteringModeDescription": { - "message": "Advanced network filtering plus specific and generic extended filtering from selected filter lists.\n\nRequires broad permission to read and modify data on all websites.\n\nGeneric extended filtering may cause higher webpage resources usage.", + "message": "තෝරාගත් පෙරහන් ලැයිස්තු වලින් උසස් ජාල පෙරහන් සහ විශේෂිත සහ සාමාන්‍ය දිගු පෙරහන්.\n\nසියලුම වෙබ් අඩවි වල දත්ත කියවීමට සහ වෙනස් කිරීමට පුළුල් අවසරයක් අවශ්‍ය වේ.\n\nසාමාන්‍ය දිගු පෙරහන් මඟින් වෙබ් පිටු සම්පත් භාවිතය ඉහළ යාමට හේතු විය හැක.", "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { @@ -232,51 +248,167 @@ "description": "Label for a checkbox in the options page" }, "enableStrictBlockLabel": { - "message": "Enable strict blocking", + "message": "දැඩි අවහිර කිරීම සක්‍රීය කරන්න", "description": "Label for a checkbox in the options page" }, "enableStrictBlockLegend": { - "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "message": "අනවශ්‍ය විය හැකි අඩවි වෙත සංචාලනය අවහිර කරනු ලබන අතර, ඉදිරියට යාමට ඔබට විකල්පය ලබා දෙනු ඇත.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { - "message": "Find lists", + "message": "ලැයිස්තු සොයන්න", "description": "Placeholder for the input field used to find lists" }, "strictblockTitle": { - "message": "Page blocked", + "message": "පිටුව අවහිරයි", "description": "Webpage title for the strict-blocked page" }, "strictblockSentence1": { - "message": "uBO Lite has prevented the following page from loading:", + "message": "uBO Lite විසින් පහත පිටුව පූරණය වීම වළක්වා ඇත:", "description": "Sentence used in the strict-blocked page" }, "strictblockReasonSentence1": { - "message": "The page was blocked because of a matching filter in {{listname}}.", + "message": "{{listname}}හි ගැළපෙන පෙරහනක් නිසා පිටුව අවහිර කරන ලදී.", "description": "Text informing about what is causing the page to be blocked" }, "strictblockRedirectSentence1": { - "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", + "message": "අවහිර කළ පිටුව වෙනත් අඩවියකට හරවා යැවීමට අවශ්‍යයි. ඔබ ඉදිරියට යාමට තෝරා ගන්නේ නම්, ඔබ කෙලින්ම මෙහි සංචාලනය කරනු ඇත: {{url}}", "description": "Text warning about an incoming redirect" }, "strictblockNoParamsPrompt": { - "message": "without parameters", + "message": "පරාමිතීන් නොමැතිව", "description": "Label to be used for the parameter-less URL" }, "strictblockBack": { - "message": "Go back", + "message": "ආපසු යන්න", "description": "A button to go back to the previous webpage" }, "strictblockClose": { - "message": "Close this window", + "message": "මෙම කවුළුව වසන්න", "description": "A button to close the current tab" }, "strictblockDontWarn": { - "message": "Don't warn me again about this site", + "message": "මෙම අඩවිය ගැන මට නැවත අනතුරු අඟවන්න එපා.", "description": "Label for checkbox in document-blocked page" }, "strictblockProceed": { - "message": "Proceed", + "message": "ඉදිරියට", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "මූලද්‍රව්‍ය zapper ප්‍රකාරයට ඇතුළු වන්න", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "මූලද්‍රව්‍ය zapper ප්‍රකාරයෙන් ඉවත් වන්න", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/sk/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/sk/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/sk/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/sk/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Nastavenia", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Vlastné filtre", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Vývoj", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "O doplnku", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "Režim filtrovania", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Na tejto webovej stránke", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Nahlásiť problém na tejto webovej stránke", + "message": "Nahlásiť problém", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -60,7 +72,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Domény malvéru", + "message": "Ochrana pred škodlivým softvérom, bezpečnosť", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -75,6 +87,14 @@ "message": "Regióny, jazyky", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import/export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Sem vložte špecifické kozmetické filtre, ktoré chcete pridať", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Zoznam zmien", "description": "" @@ -111,12 +131,16 @@ "message": "Nahlásenie problémov s filtrom s konkrétnymi webovými stránkami na uBlockOrigin/uAssets issue tracker. Vyžaduje sa GitHub účet.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Informácie o riešení problémov", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Aby ste dobrovoľníkov nezaťažovali duplicitnými hláseniami, overte si, či už problém nebol nahlásený.", + "message": "Aby ste dobrovoľníkov nezaťažovali duplicitnými hláseniami, overte si, či už problém nebol nahlásený. Poznámka: kliknutím na tlačidlo sa odošle pôvodná stránka na GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Vyhľadať podobné hlásenia", + "message": "Vyhľadať podobné hlásenia na Githube", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Vytvoriť nové hlásenie", + "message": "Vytvoriť nové hlásenie na Githube", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Vitajte", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Práve ste nainštalovali uBO Lite. Tu si môžete vybrať predvolený režim filtrovania, ktorý sa má používať na všetkých webových stránkach.\n\nV predvolenom nastavení je zvolený režim Základný, pretože nevyžaduje povolenie na čítanie a zmenu údajov. Ak dôverujete rozšíreniu uBO Lite, môžete mu udeliť všeobecné oprávnenie na čítanie a zmenu údajov na všetkých webových stránkach, aby ste v predvolenom nastavení umožnili pokročilejšie možnosti filtrovania všetkých webových stránok.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Predvolený režim filtrovania", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigácia na potenciálne nežiaduce stránky sa zablokuje a ponúkne sa vám možnosť pokračovať.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Vývojársky režim", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Umožňuje prístup k funkciám vhodným pre technických používateľov.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Zálohovať/Obnoviť", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Zálohujte si vlastné nastavenia do súboru alebo obnovte vlastné nastavenia zo súboru.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Obnovením sa prepíšu všetky vaše aktuálne vlastné nastavenia.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Nájsť zoznamy", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Pokračovať", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Odstrániť prvok", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Ukončiť režim dočasného skrytia prvkov", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Vytvoriť vlastný filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Odstrániť vlastný filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Zobraziť:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Podrobnosti režimu filtrovania", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Vlastné pravidlá DNR", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Pravidlá DNR…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamický súbor pravidiel", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Súbor pravidiel relácie", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Uložiť", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Vrátiť späť", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Pridať", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Importovať a pripojiť…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exportovať…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Zálohovať…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Obnoviť…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Nepridávajte obsah z nedôveryhodných zdrojov", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Počet zaregistrovaných pravidiel: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Posunutím jazdca vyberte najlepšiu zhodu", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Vybrať", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Náhľad", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Vytvoriť", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Vyberte filter na zvýraznenie zodpovedajúcich prvkov na webovej stránke. Ak chcete filter odstrániť, kliknite na kôš.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/sl/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/sl/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/sl/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/sl/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "A permission-less content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", + "message": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Report an issue", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Regions, languages", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Changelog", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/so/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/so/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/so/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/so/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "A permission-less content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", + "message": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Report an issue", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Regions, languages", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Changelog", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/sq/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/sq/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/sq/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/sq/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Një bllokues që bllokon në mënyrë të pavarur reklamat, gjurmuesit, kriptominatorët etj. menjëherë pas instalimit.", + "message": "Një bllokues efikas për reklamat, gjurmuesit, kriptominatorët e të tjera, që vepron menjëherë pas instalimit.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Parametrat", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Filtrat e personalizuar", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Zhvillimi", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Info", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "mënyra e filtrimit", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Në këtë uebsajt", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Raportoj problemin me uebsajtin", + "message": "Raportoj problemin", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -60,7 +72,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Domenet e dëmshme", + "message": "Domenet e dëmshme, siguria", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -75,6 +87,14 @@ "message": "Sipas rajonit, gjuhës", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Importoj / Eksportoj", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Filtrat specifikë të personalizuar kalohen këtu", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Ditari i ndryshimeve", "description": "" @@ -111,12 +131,16 @@ "message": "Problemet e disa faqeve me filtrat duhen raportuar në ditarin e problemeve uBlockOrigin/uAssets. Duhet një konto GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Diagnostikimi i problemeve", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Verifikoni a është raportuar më parë problemi që të mos i lodhni vullnetarët e tjerë me të njëjtat gjëra.", + "message": "Verifikoni a është raportuar edhe më parë që të mos i lodhni vullnetarët e tjerë me të njëjtat probleme. Shënim: kur klikoni butonin, origjina e faqes do të dërgohet në GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Gjej raporte të ngjashme", + "message": "Gjej raporte të ngjashme në GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Krijoj raport të ri", + "message": "Krijoj raport të ri në GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Përshëndetje", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Sapo instaluat uBO Lite. Këtu mund të zgjidhni mënyrën e filtrimit që duhet përdorur për të gjitha uebsajtet.\n\nE thjeshta është mënyra standarde, sepse nuk ju merret leje për leximin dhe modifikimin e të dhënave. Nëse keni besim te uBO Lite, mund t'i jepni leje shtesë për leximin dhe modifikimin e të dhënave në të gjitha uebsajtet, në mënyrë që të kryeni një filtrim më të avancuar.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Mënyra standarde e filtrimit", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Uebsajtet potencialisht të padëshirueshme do të bllokohen dhe do t'ju jepet mundësia për të vazhduar.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Këndi i zhvilluesit", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Mundëson qasjen në funksione të përshtatshme për përdoruesit teknikë.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Kopja rezervë", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Mbani një kopje rezervë të parametrave që keni personalizuar ose riktheni parametrat e mëparshëm.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Rikthimi do të fshijë gjithë parametrat që keni personalizuar.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Gjej listat", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Vazhdoj", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Heq elementin", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Mbyll asgjësuesin e elementeve", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Krijoj filtër të personalizuar", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Heq filtrin e personalizuar", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Pamja:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Detajet e mënyrës së filtrimit", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Rregullat DNR të personalizuara", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Rregullat DNR të…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Rregullat dinamike", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Rregullat e seancës", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Regjistroj", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Rikthej", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Shtoj", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Importoj dhe shtoj…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Eksportoj…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Rezervoj…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Rikthej…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Mos shtoni materiale nga burime të pabesueshme", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Numri i rregullave të regjistruara: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Lëvizeni për të zgjedhur pikën më të përshtatshme", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Zgjedh", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Parashikoj", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Krijoj", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Zgjidhni ndër filtrat më poshtë për të parë elementin që i korrespondon në faqe. Filtrat hiqen duke klikuar koshin.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/sr/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/sr/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/sr/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/sr/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Подешавања", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Прилагођени филтери", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Развити", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "О апликацији", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "режим филтрирања", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "На овој веб страници", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "Пријавите проблем на овом веб сајту", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "Регионални, језички", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Увоз / извоз", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Овде налепите одређене козметичке филтере које желите додати", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Списак измена", "description": "" @@ -111,6 +131,10 @@ "message": "Пријавите проблеме са филтерима на одређеним веб сајтовима на uBlockOrigin/uAssets issue tracker. Захтева GitHub налог.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Информације о решавању проблема", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { "message": "Да не бисте оптерећивали волонтере дуплим извештајима, проверите да ли је проблем већ пријављен.", "description": "A paragraph in the filter issue reporter section" @@ -167,14 +191,6 @@ "message": "Креирај нови извештај", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Добродошли", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Управо сте инсталирали uBO Lite. Овде можете изабрати подразумевани режим филтрирања који ће се користити на свим сајтовима.\n\nПодразумевано је изабран основни режим јер он не захтева дозволу за читање и мењање података. Ако верујете uBO Lite-у, можете му дати широку дозволу за читање и мењање података како би се подразумевано омогућиле напредније могућности филтрирања за све сајтове.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Подразумевани режим филтрирања", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Навигација до потенцијално непожељних сајтова ће бити блокирана и биће вам понуђена опција да наставите.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Режим за програмере", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Омогућава приступ функцијама погодним за техничке кориснике.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Пронађи листе", "description": "Placeholder for the input field used to find lists" @@ -252,11 +288,11 @@ "description": "Sentence used in the strict-blocked page" }, "strictblockReasonSentence1": { - "message": "The page was blocked because of a matching filter in {{listname}}.", + "message": "Страница је блокирана због одговарајућег филтера у {{listname}}.", "description": "Text informing about what is causing the page to be blocked" }, "strictblockRedirectSentence1": { - "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", + "message": "Блокирана страница жели да преусмери на други сајт. Ако одлучите да наставите, бићете директно на: {{url}}", "description": "Text warning about an incoming redirect" }, "strictblockNoParamsPrompt": { @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Настави", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Уклоните елемент", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Изађи из режима за затварање елемената", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Направите прилагођени филтер", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Уклоните прилагођени филтер", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Приказ:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Детаљи режима филтрирања", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Прилагођена правила за DNR", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "ДНР правила …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Динамички скуп правила", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Скуп правила сесије", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Сачувај", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Врати", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Додај", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Увези и додај…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Извоз…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Не додајте садржај из непоузданих извора", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Број регистрованих правила: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Померите клизач да бисте изабрали најбоље подударање", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Изаберите", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Прегледај", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Креирај", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Изаберите филтер испод да бисте истакли одговарајуће елементе на веб страници. Кликните на канту за смеће да бисте уклонили филтер.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/sv/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/sv/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/sv/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/sv/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "En behörighetslös innehållsblockerare. Blockerar annonser, spårare, miners och mer omedelbart efter installationen.", + "message": "En effektiv innehållsblockerare. Blockerar annonser, spårare, miners och mer direkt efter den har installerats.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Inställningar", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Anpassade filter", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Utveckla", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Om", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtreringsläge", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "På denna webbplats", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Rapportera ett problem på denna webbplats", + "message": "Rapportera ett problem", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -60,7 +72,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Domäner med skadlig kod (malware)", + "message": "Skydd mot skadlig programvara, säkerhet", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -75,6 +87,14 @@ "message": "Regioner, språk", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Importera / Exportera", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Här klistrar du in specifika kosmetiska filter att lägga till", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Ändringslogg", "description": "" @@ -111,12 +131,16 @@ "message": "Rapportera filterproblem med specifika webbplatser till uBlockOrigin/uAssets problemhanteringssystemet. Kräver ett GitHub-konto.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Felsökningsinformation", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "För att undvika att belasta volontärer med dubbletter av rapporter, kontrollera att problemet inte redan har rapporterats.", + "message": "För att undvika att belasta volontärer med dubbletter av rapporter, kontrollera att problemet inte redan har rapporterats. Observera: om du klickar på knappen kommer sidans ursprung att skickas till GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Hitta liknande rapporter", + "message": "Hitta liknande rapporter på GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Skapa ny rapport", + "message": "Skapa ny rapport på GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Välkommen", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Du har precis installerat uBO Lite. Här kan du välja standardfiltreringsläget som ska användas på alla webbplatser.\n\nSom standard är läget Grundläggande valt eftersom det inte kräver behörighet att läsa och ändra data. Om du litar på uBO Lite kan du ge den högre behörighet att läsa och ändra data på alla webbplatser för att som standard aktivera mer avancerade filtreringsmöjligheter för alla webbplatser.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Standardfiltreringsläge", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigering till potentiellt oönskade webbplatser kommer att blockeras och du kommer att erbjudas alternativet att fortsätta.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Utvecklarläge", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Aktivera åtkomst till funktioner som är lämpliga för tekniska användare.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Säkerhetskopiering", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Säkerhetskopiera dina anpassade inställningar till en fil, eller återställ dina anpassade inställningar från en fil.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Återställningen kommer att skriva över alla dina nuvarande anpassade inställningar.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Hitta listor", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Fortsätt", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Ta bort ett element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Lämna elementzapperläge", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Skapa ett anpassat filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Ta bort ett anpassat filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Visa:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtrera lägesdetaljer", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Anpassade DNR-regler", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR-regler av …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamisk regeluppsättning", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Sessionsregeluppsättning", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Spara", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Ångra", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Lägg till", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Importera och lägg till…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exportera…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Säkerhetskopiera…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Återställ…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Lägg inte till filter från obetrodda källor.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Antal registrerade regler: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Flytta reglaget för att välja den bästa matchningen", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Välj", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Förhandsgranska", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Skapa", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Välj ett filter nedan för att markera matchande element på webbsidan. Klicka på papperskorgen för att ta bort ett filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/sw/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/sw/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/sw/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/sw/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "A permission-less content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", + "message": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Report an issue", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Regions, languages", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Changelog", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ta/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ta/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ta/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ta/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "A permission-less content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", + "message": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Report an issue", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Regions, languages", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Changelog", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/te/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/te/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/te/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/te/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "A permission-less content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", + "message": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "ఐచ్చికాలు", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "మా గురించి", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "వడపోత మోడ్", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Report an issue", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "Regions, languages", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Changelog", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/th/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/th/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/th/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/th/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,23 +4,31 @@ "description": "extension name." }, "extShortDesc": { - "message": "A permission-less content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", + "message": "ตัวบล็อกเนื้อหาที่มีประสิทธิภาพ บล็อกโฆษณา ตัวติดตาม ตัวขุดเหมือง และอื่นๆ ทันทีที่ติดตั้ง", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { - "message": "{{ruleCount}} rules, converted from {{filterCount}} network filters", + "message": "{{ruleCount}} กฎ แปลงจาก {{filterCount}} ตัวกรองเครือข่าย", "description": "Appears aside each filter list in the _3rd-party filters_ pane" }, "dashboardName": { - "message": "uBO Lite — Dashboard", + "message": "uBO Lite — แดชบอร์ด", "description": "English: uBO Lite — Dashboard" }, "settingsPageName": { "message": "การตั้งค่า", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "พัฒนา", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { - "message": "เกี่ยวกับเรา", + "message": "เกี่ยวกับ", "description": "appears as tab name in dashboard" }, "aboutPrivacyPolicy": { @@ -31,24 +39,28 @@ "message": "โหมดตัวกรอง", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "บนเว็บไซต์นี้", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "รายงานปัญหาที่เกิดบนเว็บไซต์นี้", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { - "message": "Open the dashboard", + "message": "เปิดแดชบอร์ด", "description": "English: Click to open the dashboard" }, "popupMoreButton": { - "message": "More", + "message": "ขยาย", "description": "Label to be used to show popup panel sections" }, "popupLessButton": { - "message": "Less", + "message": "ย่อลง ", "description": "Label to be used to hide popup panel sections" }, "3pGroupDefault": { - "message": "Default", + "message": "ค่าเริ่มต้น", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAds": { @@ -56,39 +68,47 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupPrivacy": { - "message": "Privacy", + "message": "ความเป็นส่วนตัว", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware protection, security", + "message": "การป้องกันมัลแวร์ ความปลอดภัย", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { - "message": "Annoyances", + "message": "ความรำคาญ", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMisc": { - "message": "Miscellaneous", + "message": "เบ็ดเตล็ด", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupRegions": { - "message": "Regions, languages", + "message": "ภูมิภาค, ภาษา", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "บันทึการเปลี่ยนแปลง", "description": "" }, "aboutCode": { - "message": "Source code (GPLv3)", + "message": "ซอร์สโค้ด (GPLv3)", "description": "English: Source code (GPLv3)" }, "aboutContributors": { - "message": "Contributors", + "message": "ผู้สนับสนุน", "description": "English: Contributors" }, "aboutSourceCode": { - "message": "Source code", + "message": "ซอร์สโค้ด", "description": "Link text to source code repo" }, "aboutTranslations": { @@ -96,95 +116,91 @@ "description": "Link text to translations repo" }, "aboutFilterLists": { - "message": "Filter lists", + "message": "รายการตัวกรอง", "description": "Link text to uBO's own filter lists repo" }, "aboutDependencies": { - "message": "External dependencies (GPLv3-compatible):", + "message": "การพึ่งพิงภายนอก (เข้ากันได้กับ GPLv3):", "description": "Shown in the About pane" }, "supportS6H": { - "message": "Report a filter issue", + "message": "รายงานปัญหาตัวกรอง", "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS3P1": { - "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", + "message": "รายงานปัญหาตัวกรองผ่านเว็บไซต์เฉพาะที่ uBlockOrigin/uAssets ปัญหาตัวติดตาม. ต้องใช้บัญชี GitHub", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "ข้อมูลการแก้ไขปัญหา", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "เพื่อเป็นการลดภาระอาสาสมัครจากการรายงานซ้ำซ้อน โปรดตรวจสอบก่อนว่าปัญหาดังกล่าวได้รับการรายงานไปแล้วหรือยัง หมายเหตุ: คลิกที่ปุ่มจะเป็นการส่งต้นทางของหน้าเว็บไปยัง GitHub", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "ค้นหารายงานที่คล้ายกันบน GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { - "message": "Address of the webpage:", + "message": "ที่อยู่ของเว็บเพจ:", "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "The webpage…", + "message": "เว็บเพจ…", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { - "message": "-- Pick an entry --", + "message": "-- เลือกรายการ --", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { - "message": "Shows ads or ad leftovers", + "message": "แสดงโฆษณาหรือสิ่งที่ตกค้างอยู่", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "Has overlays or other nuisances", + "message": "มีโอเวอร์เลย์หรือสิ่งอื่น ๆ ที่รบกวน", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { - "message": "Detects uBO Lite", + "message": "ตรวจหา uBlock Origin", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { - "message": "Has privacy-related issues", + "message": "มีปัญหาเกี่ยวกับความเป็นส่วนตัว", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "Malfunctions when uBO Lite is enabled", + "message": "ความผิดปกติเมื่อเปิดใช้งาน uBO Lite", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { - "message": "Opens unwanted tabs or windows", + "message": "เปิดแท็บหรือหน้าต่างที่ไม่ต้องการ", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { - "message": "Leads to badware, phishing", + "message": "นำไปสู่แบดแวร์ ฟิชชิ่ง", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { - "message": "Label the webpage as “NSFW” (“Not Safe For Work”)", + "message": "ติดป้ายเว็บเพจว่าเป็น “NSFW” (“ไม่ปลอดภัยกับงาน (Not Safe For Work)”)", "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { "message": "สร้างรายงานใหม่", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "ยินดีต้อนรับ", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "คุณเพิ่งติดตั้ง uBO Lite คุณสามารถเลือกโหมดการกรอง (ค่าเริ่มต้น) ที่จะใช้กับเว็บไซต์ทั้งหมดได้ที่นี่\n\nตามค่าเริ่มต้น โหมด พื้นฐาน จะถูกเลือกเนื่องจากไม่จำเป็นต้องมีสิทธิ์ในการอ่านและแก้ไขข้อมูล หากคุณไว้วางใจ uBO Lite คุณสามารถให้สิทธิ์ในการอ่านและแก้ไขข้อมูลบนเว็บไซต์ทั้งหมดได้ เพื่อเปิดใช้งานคุณสมบัติการกรองข้อมูลขั้นสูงสำหรับเว็บไซต์ทั้งหมดตามค่าเริ่มต้น", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "โหมดการกรองเริ่มต้น", "description": "The header text for the default filtering mode section" }, "defaultFilteringModeDescription": { - "message": "The default filtering mode will be overridden by per-website filtering modes. You can adjust the filtering mode on any given website according to whichever mode works best on that website. Each mode has its advantages and disadvantages.", + "message": "โหมดการคัดกรองเริ่มต้นจะถูกแทนที่ด้วยโหมดการคัดกรองเฉพาะเว็บไซต์ คุณสามารถปรับแต่งโหมดคัดกรองสำหรับเว็บไซต์ที่มีตามโหมดใดก็ได้ที่ทำงานได้ดีที่สุดบนเว็บไซต์นั้น ซึ่งแต่ละโหมดก็มีข้อดีข้อเสีย", "description": "This describes the default filtering mode setting" }, "filteringMode0Name": { - "message": "no filtering", + "message": "ไม่มีการคัดกรอง", "description": "Name of blocking mode 0" }, "filteringMode1Name": { @@ -192,27 +208,27 @@ "description": "Name of blocking mode 1" }, "filteringMode2Name": { - "message": "optimal", + "message": "เหมาะสมที่สุด", "description": "Name of blocking mode 2" }, "filteringMode3Name": { - "message": "complete", + "message": "สมบูรณ์", "description": "Name of blocking mode 3" }, "basicFilteringModeDescription": { - "message": "Basic network filtering from selected filter lists.\n\nDoes not require permission to read and modify data on websites.", + "message": "การคัดกรองเครือข่ายเบื้องต้นจากรายการที่เลือก\n\nไม่ต้องขออนุญาตในการอ่านและปรับแต่งข้อมูลบนเว็บไซต์", "description": "This describes the 'basic' filtering mode" }, "optimalFilteringModeDescription": { - "message": "Advanced network filtering plus specific extended filtering from selected filter lists.\n\nRequires broad permission to read and modify data on all websites.", + "message": "การคัดกรองเครือข่ายขั้นสูงและการคัดกรองเพิ่มเติมโดยเฉพาะจากรายการที่เลือก\n\nต้องขออนุญาตแบบรวมในการอ่านและปรับแต่งข้อมูลบนทุกเว็บไซต์", "description": "This describes the 'optimal' filtering mode" }, "completeFilteringModeDescription": { - "message": "Advanced network filtering plus specific and generic extended filtering from selected filter lists.\n\nRequires broad permission to read and modify data on all websites.\n\nGeneric extended filtering may cause higher webpage resources usage.", + "message": "การคัดกรองเครือข่ายขั้นสูงและการคัดกรองทั่วไปเพิ่มเติม และโดยเฉพาะจากรายการที่เลือก\n\nต้องขออนุญาตแบบรวมในการอ่านและปรับแต่งข้อมูลบนทุกเว็บไซต์\n\nการคัดกรองทั่วไปเพิ่มเติมอาจะทำให้มีการใช้งานทรัพยากรเว็บเพจสูงขึ้น", "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of websites for which no filtering will take place.", + "message": "รายการเว็บไซต์ซึ่งไม่มีการคัดกรอง", "description": "A short description for the editable field which lists trusted sites" }, "noFilteringModePlaceholder": { @@ -232,51 +248,167 @@ "description": "Label for a checkbox in the options page" }, "enableStrictBlockLabel": { - "message": "Enable strict blocking", + "message": "เปิดใช้งานการบล๊อกเข็มงวด", "description": "Label for a checkbox in the options page" }, "enableStrictBlockLegend": { - "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "message": "การนำทางไปยังเว็บไซต์ที่ไม่พึงประสงค์จะถูกบล็อก และคุณจะได้รับตัวเลือกเพื่อดำเนินการต่อ", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "โหมดนักพัฒนา", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "เปิดใช้งานฟีเจอร์สำหรับผู้ใช้ทางเทคนิค", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { - "message": "Find lists", + "message": "หารายการ", "description": "Placeholder for the input field used to find lists" }, "strictblockTitle": { - "message": "Page blocked", + "message": "บล๊อกเพจ", "description": "Webpage title for the strict-blocked page" }, "strictblockSentence1": { - "message": "uBO Lite has prevented the following page from loading:", + "message": "uBO Lite ได้ป้องกันเพจเหล่านี้จากการโหลด:", "description": "Sentence used in the strict-blocked page" }, "strictblockReasonSentence1": { - "message": "The page was blocked because of a matching filter in {{listname}}.", + "message": "เว็บเพจถูกบล๊อก เพราะตรงกับรายการคัดกรองใน {{listname}}.", "description": "Text informing about what is causing the page to be blocked" }, "strictblockRedirectSentence1": { - "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", + "message": "เว็บเพจที่บล๊อกต้องการเด้งไปเว็บไซต์อื่น หากคุณต้องการดำเนินการต่อ คุณจะถูกนำทางโดยตรงไปที่: {{url}}", "description": "Text warning about an incoming redirect" }, "strictblockNoParamsPrompt": { - "message": "without parameters", + "message": "ไม่ระบุพารามิเตอร์", "description": "Label to be used for the parameter-less URL" }, "strictblockBack": { - "message": "Go back", + "message": "ย้อนกลับ", "description": "A button to go back to the previous webpage" }, "strictblockClose": { - "message": "Close this window", + "message": "ปิดหน้าต่างนี้", "description": "A button to close the current tab" }, "strictblockDontWarn": { - "message": "Don't warn me again about this site", + "message": "อย่าเตือนเกี่ยวกับเว็บไซต์นี้ให้กับฉันอีก", "description": "Label for checkbox in document-blocked page" }, "strictblockProceed": { - "message": "Proceed", + "message": "ดำเนินต่อ", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "ลบองค์ประกอบ", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "ออกจากโหมดลบองค์ประกอบ", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "สร้างตัวกรองที่กำหนดเอง", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "ลบตัวกรองที่กำหนดเอง", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "ดู:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "รายละเอียดโหมดการกรอง", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "กฎ DNR ที่กำหนดเอง", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "กฎ DNR ของ…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "ชุดกฎไดนามิก", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "ชุดกฎเซสชัน", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "บันทึก", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "ย้อนกลับ", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "นำเข้าและต่อท้าย…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "ส่งออก…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "อย่าเพิ่มเนื้อหาจากแหล่งที่ไม่น่าเชื่อถือ", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "จำนวนกฎที่ลงทะเบียน: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "เลื่อนแถบเลื่อนเพื่อเลือกรายการที่ตรงกันที่สุด", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "เลือก", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "แสดงตัวอย่าง", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "สร้าง", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "เลือกตัวกรองด้านล่างเพื่อไฮไลต์องค์ประกอบที่ตรงกันในหน้าเว็บ คลิกที่ไอคอนถังขยะเพื่อลบตัวกรอง", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/tr/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/tr/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/tr/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/tr/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "İzin gerektirmeyen içerik engelleyicisi. Kurulumdan hemen sonra reklamları, izleyicileri, ve daha fazlasını engeller.", + "message": "Etkili bir içerik engelleyici. Reklamları, izleyicileri, madencileri ve daha fazlasını kurulumdan hemen sonra engeller.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,14 @@ "message": "Ayarlar", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Özel filtreler", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Geliştir", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Hakkında", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "Filtreleme modu", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Bu web sitesinde", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "Bu sitedeki bir sorunu bildir", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "Bölgeler, diller", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "İçeri/Dışarı aktar", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Eklenmesi için kozmetik filtreleri buraya yapıştırın", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Değişiklik günlüğü", "description": "" @@ -108,15 +128,19 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS3P1": { - "message": "Bir sitedeki filtre sorunlarını bildirmek için uBlockOrigin/uAssets issue tracker kullanın. Bir GitHub hesabı gerekir.", + "message": "Bir sitedeki filtre sorunlarını bildirmek için uBlockOrigin/uAssets sorun takibi sayfasını kullanın. Bir GitHub hesabı gerekir.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Sorun giderme bilgisi", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Gönüllüleri benzer raporlar ile bezdirmemek için sorunun zaten bildirilip bildirilmediğine bakın.", + "message": "Gönüllüleri benzer raporlar ile bezdirmemek için sorunun zaten bildirilip bildirilmediğine bakın. Not: Butona tıklamak sayfanın temel adresini GitHub'a gönderir.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Benzer raporları bul", + "message": "GitHub'da benzer raporları bul", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -136,7 +160,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "Arayüzde kaplamalar veya diğer sıkıntıları var", + "message": "Arayüzde kaplamalar veya diğer can sıkıcı ögeler var", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { @@ -156,7 +180,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { - "message": "Kötü niyetli yazılıma yönlendiriyor, oltalama", + "message": "Kötü niyetli yazılıma, oltalamaya yönlendiriyor", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Yeni rapor oluştur", + "message": "GitHub'da yeni rapor oluştur", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Hoş geldiniz", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Az önce uBO Lite'ı indirdiniz. Buradan tüm siteler için varsayılan filtreleme modlarını seçebilirsiniz.\n\nVarsayılan olarak, Basit mod seçilidir çünkü verileri okuma ve yazma izni gerektirmez. uBO Lite'a güveniyorsanız, tüm sitelerde verileri okuma ve yazma izni verebilirsiniz ve daha gelişmiş filtreleme yeteneklerine tüm sitelerde sahip olabilirsiniz.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Varsayılan filtreleme modu", "description": "The header text for the default filtering mode section" @@ -216,7 +232,7 @@ "description": "A short description for the editable field which lists trusted sites" }, "noFilteringModePlaceholder": { - "message": "[sadece ana bilgisayar adları]\nörnek.com\noyunlar.site\n…", + "message": "[sadece alan adları]\norneksite.com\noyunlar.site\n…", "description": "Default text for in edit field" }, "behaviorSectionLabel": { @@ -232,13 +248,33 @@ "description": "Label for a checkbox in the options page" }, "enableStrictBlockLabel": { - "message": "Sıkı engellemeyi kullanıma al", + "message": "Sıkı engellemeyi etkinleştir", "description": "Label for a checkbox in the options page" }, "enableStrictBlockLegend": { - "message": "İstenmeyebilecek sitelere giriş engellenecek ve devam edip etmeyeceğiniz size sorulacak.", + "message": "İstenmeyebilecek sitelere erişim engellenecek ve devam etme seçeneği sunulacaktır.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Geliştirici modu", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Teknik kullanıcılara uygun özelliklere erişime izin ver.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Yedekle", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Ayarlarınızı bir dosyaya yedekleyin veya yedeklenmiş bir dosyadan alın.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Yedekten geri yükleyince şu anki ayarlarınızın yerine geçecek.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Liste bul", "description": "Placeholder for the input field used to find lists" @@ -252,7 +288,7 @@ "description": "Sentence used in the strict-blocked page" }, "strictblockReasonSentence1": { - "message": "Bu sayfa {{listname}} içindeki bir süzgece takıldığı için engellenmiştir.", + "message": "Bu sayfa {{listname}} içindeki bir filtreye takıldığı için engellenmiştir.", "description": "Text informing about what is causing the page to be blocked" }, "strictblockRedirectSentence1": { @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Devam et", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Öge silme moduna gir", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Öge silme modundan çık", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Özel filtre oluştur", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Özel filtreyi kaldır", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Görünüm:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtreleme modu ayrıntıları", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Özel DNR kuralları", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR kuralları …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dinamik kural seti", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Oturum kural seti", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Kaydet", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Geri al", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Ekle", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "İçe aktar ve ekle…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Dışa aktar…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Yedekle…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Geri yükle…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Güvenilmeyen kaynaklardan içerik eklemeyin", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Kayıtlı kural sayısı: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "En iyi eşleşmeyi seçmek için kaydırıcıyı hareket ettir", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Seç", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Ön İzle", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Oluştur", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Web sayfasındaki eşleşen öğeleri vurgulamak için aşağıdan bir filtre seçin. Bir filtreyi kaldırmak için çöp kutusuna tıklayın.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/uk/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/uk/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/uk/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/uk/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Налаштування", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Розробка", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Про застосунок", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "режим фільтрації", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "На цьому вебсайті", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "Повідомити про помилку на цьому вебсайті", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "Регіони, мови", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Журнал змін", "description": "" @@ -111,8 +131,12 @@ "message": "Повідомляйте про вади з фільтрами на конкретних вебсайтах у відстежувач помилок uBlockOrigin/uAssets. Потрібен обліковий запис GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Усунення проблем", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "Щоб не обтяжувати волонтерів повторюваними звітами, переконайтеся, що про проблему ще не повідомлялося.", + "message": "Щоб не обтяжувати волонтерів повторюваними звітами, переконайтеся, що про проблему ще не повідомлялося.Зауваження: натискання на кнопку призведе до надсилання походження сторінки на GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { @@ -167,14 +191,6 @@ "message": "Створити новий звіт", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Ласкаво просимо", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Ви щойно встановили uBO Lite. Тут ви можете вибрати режим фільтрації за замовчуванням, який буде використовуватися на всіх вебсайтах.\n\nЗа замовчуванням вибрано Базовий режим, оскільки він не вимагає дозволу на читання та зміну даних. Якщо ви довіряєте uBO Lite, ви можете надати йому широкий дозвіл на читання та зміну даних на всіх вебсайтах, щоб увімкнути більш розширені можливості фільтрації для всіх вебсайтів за замовчуванням.\n", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Типовий режим фільтрування", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Перехід до потенційно небажаних сайтів буде заблоковано, та вам буде запропоновано можливість продовжити", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Режим розробника", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Відкрити доступ до можливостей, які актуальні для технічних користувачів", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Знайти списки", "description": "Placeholder for the input field used to find lists" @@ -248,7 +284,7 @@ "description": "Webpage title for the strict-blocked page" }, "strictblockSentence1": { - "message": "uBO Lite заблокував завантаження наступних сторінок:", + "message": "uBO Lite заблокував завантаження таких сторінок:", "description": "Sentence used in the strict-blocked page" }, "strictblockReasonSentence1": { @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Продовжити", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Перейти в режим тимчасового приховування елементів", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Вийти з режиму тимчасового приховування елементів", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Створити власний фільтр", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Вилучити власний фільтр", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Перегляд:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Подробиці режиму фільтрації", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Користувацькі правила DNR", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Правила DNR для…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Динамічний набір правил", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Набір правил для сесії", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Зберегти", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Повернути", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Імпортувати та додати…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Експортувати…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Не додавати вміст з невідомих джерел", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Кількість зареєстрованих правил: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Переміщайте повзунок для вибору кращого варіанту", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Вибрати", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Попередній перегляд", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Створити", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Виберіть фільтр нижче, щоб підсвітити відповідні елементи на сторінці. Натисніть на кошик для видалення фільтра.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ur/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ur/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/ur/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/ur/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "ترتیبات", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "تعارف", "description": "appears as tab name in dashboard" @@ -31,8 +39,12 @@ "message": "فلٹرنگ موڈ", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "Report an issue", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { @@ -75,6 +87,14 @@ "message": "علاقے، زبانیں۔", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "چینج لاگ", "description": "" @@ -111,12 +131,16 @@ "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS6URL": { @@ -164,17 +188,9 @@ "description": "A checkbox to use for NSFW sites" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "خوش آمدید", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "آپ نے ابھی یو بی او لائٹ انسٹال کیا ہے۔ یہاں آپ تمام ویب سائٹس پر استعمال کرنے کے لیے ڈیفالٹ فلٹرنگ موڈ کا انتخاب کر سکتے ہیں۔\n\nپہلے سے طے شدہ طور پر، بنیادی موڈ کو منتخب کیا جاتا ہے کیونکہ اسے ڈیٹا کو پڑھنے اور اس میں ترمیم کرنے کی اجازت کی ضرورت نہیں ہوتی ہے۔ اگر آپ کو uBO Lite پر بھروسہ ہے، تو آپ اسے تمام ویب سائٹس پر ڈیٹا کو پڑھنے اور اس میں ترمیم کرنے کی وسیع اجازت دے سکتے ہیں تاکہ تمام ویب سائٹس کے لیے پہلے سے طے شدہ فلٹرنگ کی مزید جدید صلاحیتوں کو فعال کیا جا سکے۔", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "ڈیفالٹ فلٹرنگ موڈ", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Navigation to potentially undesirable sites will be blocked, and you will be offered the option to proceed.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Backup", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Back up your custom settings to a file, or restore your custom settings from a file.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Find lists", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Proceed", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Back up…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Restore…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/vi/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/vi/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/vi/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/vi/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "Cài đặt", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "Custom filters", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "Phát triển", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Giới thiệu", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "chế độ lọc", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Trên trang web này", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "Báo cáo lỗi trên trang này", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "Khu vực, ngôn ngữ", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "Import / Export", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "Paste here specific cosmetic filters to add", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "Nhật ký thay đổi", "description": "" @@ -111,6 +131,10 @@ "message": "Báo cáo các vấn đề về bộ lọc với các trang web cụ thể cho trình theo dõi vấn đề uBlockOrigin/uAssets xử lý. Cần có tài khoản GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "Thông tin chẩn đoán lỗi", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { "message": "Để tránh tạo thêm gánh nặng cho các tình nguyện viên, hãy chắc chắn rằng chưa từng có vấn đề tương tự được báo cáo.", "description": "A paragraph in the filter issue reporter section" @@ -167,14 +191,6 @@ "message": "Tạo báo cáo mới", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "Chào mừng", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "Bạn vừa cài đặt uBO Lite. Bạn có thể chọn chế độ của bộ lọc mặc định để sử dụng trên tất cả các trang web. Theo mặc định, chế độ Cơ bản được chọn vì chế độ này không yêu cầu quyền đọc và thay đổi dữ liệu. Nếu bạn tin tưởng uBO Lite, bạn có thể cấp cho bộ lọc với quyền rộng rãi để đọc và thay đổi dữ liệu trên tất cả các trang web để kích hoạt khả năng lọc nâng cao hơn cho tất cả các trang web theo mặc định.", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "Chế độ bộ lọc mặc định", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "Việc điều hướng đến các trang web có khả năng không mong muốn sẽ bị chặn và bạn sẽ được cung cấp tùy chọn để tiếp tục.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Chế độ nhà phát triển", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "Cho phép truy cập các tính năng dành cho người dùng nâng cao", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "Sao lưu", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "Sao lưu cài đặt tùy chỉnh của bạn vào một tệp hoặc khôi phục cài đặt tùy chỉnh từ một tệp.", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "Restoring will overwrite all your current custom settings.", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "Tìm danh sách", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "Tiến hành", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Chuyển sang chế độ chặn phần tử tạm thời", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Thoát khỏi chế độ chặn phần tử tạm thời", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Tạo một bộ lọc tùy chỉnh", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Xóa một bộ lọc tuỳ chỉnh", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Xem:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Chi tiết chế độ chặn", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Quy tắc DRN tùy chỉnh", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Quy tắc DRN cho ...", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Danh sách quy tắc động", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Danh sách quy tắc phiên", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Lưu", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Đặt lại", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "Add", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "Nhập và thêm vào", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Xuất…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "Sao lưu…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "Khôi phục…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "Không thêm các bộ lọc từ các nguồn không đáng tin cậy", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Số quy tắc đã đăng ký: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Di chuyển thanh trượt để chọn kết quả phù hợp nhất", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Chọn", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Xem trước", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Tạo", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Chọn một bộ lọc bên dưới để đánh dấu các phần tử phù hợp trong trang web. Nhấp vào thùng rác để xóa bộ lọc.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/zh_CN/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/zh_CN/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/zh_CN/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/zh_CN/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "设置", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "自定义过滤规则", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "开发", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "关于", "description": "appears as tab name in dashboard" @@ -31,12 +39,16 @@ "message": "过滤模式", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "在本网站上", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { - "message": "反馈该网站上的问题", + "message": "报告此网站上的问题", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipDashboard": { - "message": "在仪表板中", + "message": "打开控制面板", "description": "English: Click to open the dashboard" }, "popupMoreButton": { @@ -48,7 +60,7 @@ "description": "Label to be used to hide popup panel sections" }, "3pGroupDefault": { - "message": "预设", + "message": "默认", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAds": { @@ -75,6 +87,14 @@ "message": "区域、语言", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "导入/导出", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "在此粘贴要添加的特定元素过滤规则", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "更新日志", "description": "" @@ -111,6 +131,10 @@ "message": "将特定网站的过滤问题报告给uBlockOrigin/uAssets issue tracker需要有 GitHub 账户。", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "故障排查相关信息", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { "message": "请确认该问题未曾上报,以避免加重志愿者负担。", "description": "A paragraph in the filter issue reporter section" @@ -140,7 +164,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { - "message": "检测到 uBO Lite", + "message": "检测 uBO Lite", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { @@ -167,14 +191,6 @@ "message": "创建新报告", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "欢迎使用", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "uBO Lite 现已安装完毕。接下来您可以为网页内容选择默认过滤模式。\n\n预设过滤模式为“基础”,该模式不需要读取或修改网页内容的权限。如果您信任 uBO Lite,您可以授予其用以读取或修改所有网页数据的额外权限,进而默认为所有网站开启高级过滤模式。", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "默认过滤模式", "description": "The header text for the default filtering mode section" @@ -212,15 +228,15 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "不进行过滤的主机名列表", + "message": "不进行过滤的网站列表。", "description": "A short description for the editable field which lists trusted sites" }, "noFilteringModePlaceholder": { - "message": "[域名]\nexample.com\ngames.example\n...", + "message": "[仅限主机名]\nexample.com\ngames.example\n...", "description": "Default text for in edit field" }, "behaviorSectionLabel": { - "message": "操作设置", + "message": "行为", "description": "The header text for the 'Behavior' section" }, "autoReloadLabel": { @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "导航至潜在不良网站的操作将被拦截,并且您将可以选择继续前往。", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "开发者模式", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "启用访问适合技术用户的功能。", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "备份", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "将自定义设置备份到文件,或从文件还原自定义设置。", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "还原将覆盖当前所有自定义设置。", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "查找列表", "description": "Placeholder for the input field used to find lists" @@ -248,7 +284,7 @@ "description": "Webpage title for the strict-blocked page" }, "strictblockSentence1": { - "message": "uBO Lite 已阻止了以下页面的加载:", + "message": "uBO Lite 已阻止加载以下页面:", "description": "Sentence used in the strict-blocked page" }, "strictblockReasonSentence1": { @@ -256,7 +292,7 @@ "description": "Text informing about what is causing the page to be blocked" }, "strictblockRedirectSentence1": { - "message": "被屏蔽的页面希望重定向到另一个网站。如果您选择继续,将直接导航到:{{url}}", + "message": "被拦截的页面将重定向至其他网站。如果您选择继续,将直接导航至:{{url}}", "description": "Text warning about an incoming redirect" }, "strictblockNoParamsPrompt": { @@ -272,11 +308,107 @@ "description": "A button to close the current tab" }, "strictblockDontWarn": { - "message": "不要再警告我关于这个网站了", + "message": "不要再警告我有关此网站", "description": "Label for checkbox in document-blocked page" }, "strictblockProceed": { "message": "继续", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "进入临时移除元素模式", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "退出临时元素移除模式", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "创建自定义过滤器", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "移除自定义过滤器", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "视图:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "过滤模式详情", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "自定义DNR规则", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR规则来源:", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "动态规则集", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "会话规则集", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "保存", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "还原", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "添加", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "导入并添加…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "导出…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "备份…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "还原…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "请勿添加来自不可信来源的内容", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "已注册规则的数量:", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "移动滑块以选择最佳搭配", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "选择", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "预览", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "创建", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "选择下面的过滤器以突出显示网页中匹配的元素。点击垃圾桶可移除过滤器。", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/zh_TW/messages.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/zh_TW/messages.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/_locales/zh_TW/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/_locales/zh_TW/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,14 @@ "message": "設定", "description": "appears as tab name in dashboard" }, + "customFiltersPageName": { + "message": "自訂篩選規則", + "description": "appears as tab name in dashboard" + }, + "developPageName": { + "message": "開發", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "關於", "description": "appears as tab name in dashboard" @@ -31,6 +39,10 @@ "message": "過濾模式", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "在此網站上", + "description": "Label in the popup panel for the local tools section" + }, "popupTipReport": { "message": "回報此網站的問題", "description": "Tooltip used for the 'chat' icon in the panel" @@ -75,6 +87,14 @@ "message": "地區及語言", "description": "Header for a ruleset section in 'Filter lists pane'" }, + "customFiltersImportExportLabel": { + "message": "匯入 / 匯出", + "description": "Text label heading the import/export area of custom filters" + }, + "customFiltersImportTextareaPlaceholder": { + "message": "在這裡貼上要新增的元素隱藏篩選規則", + "description": "Placeholder text which describes the purpose of the textarea widget" + }, "aboutChangelog": { "message": "變更日誌", "description": "" @@ -111,8 +131,12 @@ "message": "將特定網站的過濾器問題回報至 uBlockOrigin/uAssets 議題追蹤器需要 GitHub 帳號。.", "description": "First paragraph of 'Filter issues' section in Support pane" }, + "supportS5H": { + "message": "疑難排解資訊", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, "supportS6P1S1": { - "message": "為避免增加志願者的負擔,請先確認該問題被尚未被回報過。", + "message": "為避免增加志願者的負擔,請先確認此問題是否已被回報過。請注意:點選按鈕會將本頁的來源傳送到 GitHub。", "description": "A paragraph in the filter issue reporter section" }, "supportFindSpecificButton": { @@ -167,14 +191,6 @@ "message": "建立新報告", "description": "Text for button which open an external webpage in Support pane" }, - "firstRunSectionLabel": { - "message": "歡迎", - "description": "The header text for the welcome message section" - }, - "firstRunDescription": { - "message": "您剛安裝了 uBO Lite。您可以在此處選擇會在所有網站上套用的預設過濾模式。\n\n預設情況下,選擇了基礎模式,因為其不需要讀取與變更資料的權限。若您信任 uBO Lite,您可以授予其讀取並變更在所有網站上資料的廣泛權限,以便為所有網站啟用進階過濾功能。", - "description": "Descriptive text shown at first install time only " - }, "defaultFilteringModeSectionLabel": { "message": "預設過濾模式", "description": "The header text for the default filtering mode section" @@ -237,8 +253,28 @@ }, "enableStrictBlockLegend": { "message": "前往潛在不良網站的導航將被阻止,您可以選擇是否繼續前往。", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "開發人員模式", "description": "Label for a checkbox in the options page" }, + "developerModeLegend": { + "message": "啟用適合技術使用者使用的功能。", + "description": "Short description for a checkbox in the options page" + }, + "settingsBackupRestoreLabel": { + "message": "備份", + "description": "The header text for the back up/restore section" + }, + "settingsBackupRestoreSummary": { + "message": "將你的自訂設定備份到檔案,或是從檔案還原你的自訂設定。", + "description": "A summary description of the back up/restore section." + }, + "settingsBackupRestoreLegend": { + "message": "還原將覆寫你目前所有的自訂設定。", + "description": "Important information about the back up/restore section." + }, "findListsPlaceholder": { "message": "尋找清單", "description": "Placeholder for the input field used to find lists" @@ -278,5 +314,101 @@ "strictblockProceed": { "message": "繼續", "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "進入元素臨時移除模式", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "離開元素臨時移除模式", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "建立自訂過濾器", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "移除自訂過濾器", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "檢視:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "過濾模式詳細資訊", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "自訂 DNR 規則", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR 規則……", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "動態規則集", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "工作階段規則集", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "儲存", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "還原", + "description": "Text for buttons used to revert changes" + }, + "addButton": { + "message": "新增", + "description": "Text for buttons used to add content" + }, + "importAndAppendButton": { + "message": "匯入並加入…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "匯出…", + "description": "Text for buttons used to export content" + }, + "backupButton": { + "message": "備份…", + "description": "Text for buttons used to back up content" + }, + "restoreButton": { + "message": "還原…", + "description": "Text for buttons used to restore content" + }, + "dnrRulesWarning": { + "message": "切勿新增來自不受信任來源的內容", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "已登錄規則數:{count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "移動滑桿以選取最佳符合", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "挑選", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "預覽", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "建立", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "選取下方的過濾器,突顯網頁中符合條件的元素。按一下回收桶可移除過濾器", + "description": "Summary description on how to use the tool to remove custom filters" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/dashboard-common.css ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/dashboard-common.css --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/dashboard-common.css 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/dashboard-common.css 2025-10-25 19:32:51.000000000 +0000 @@ -3,8 +3,6 @@ box-sizing: border-box; display: flex; flex-direction: column; - max-height: 100vh; - padding: 0 var(--default-gap-xxsmall); } body > * { width: min(640px, 100%); @@ -40,9 +38,15 @@ color: var(--info3-ink); fill: var(--info3-ink); } + input[type="number"] { width: 5em; } + +input[type="file"] { + display: none; + } + @media (max-height: 640px), (max-height: 800px) and (max-width: 480px) { .body > p, .body > ul { diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/dashboard.css ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/dashboard.css --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/dashboard.css 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/dashboard.css 2025-10-25 19:32:51.000000000 +0000 @@ -1,5 +1,10 @@ -#dashboard-nav { +header { background-color: var(--surface-1); + position: sticky; + top: 0; + z-index: 100; + } +nav { border: 0; border-bottom: 1px solid var(--border-1); display: flex; @@ -8,7 +13,7 @@ overflow-x: hidden; padding: 0; } -.tabButton { +nav > .tabButton { background-color: transparent; border: 0; border-bottom: 3px solid transparent; @@ -21,46 +26,60 @@ text-decoration: none; white-space: nowrap; } -.tabButton:focus { +nav > .tabButton:focus { outline: 0; } -.tabButton:hover { +nav > .tabButton:hover { background-color: var(--dashboard-tab-hover-surface); border-bottom-color: var(--dashboard-tab-hover-border); } body[data-pane="settings"] #dashboard-nav .tabButton[data-pane="settings"], body[data-pane="rulesets"] #dashboard-nav .tabButton[data-pane="rulesets"], +body[data-pane="filters"] #dashboard-nav .tabButton[data-pane="filters"], +body[data-pane="develop"] #dashboard-nav .tabButton[data-pane="develop"], body[data-pane="about"] #dashboard-nav .tabButton[data-pane="about"] { background-color: var(--dashboard-tab-active-surface); border-bottom: 3px solid var(--dashboard-tab-active-ink); color: var(--dashboard-tab-active-ink); fill: var(--dashboard-tab-active-ink); } +body:not([data-develop="true"]) #dashboard-nav .tabButton[data-pane="develop"] { + display: none; + } +body:not([data-pane="rulesets"]) header [data-pane-related="rulesets"] { + display: none; + } body > section { + box-sizing: border-box; display: none; - overflow: auto; - padding-bottom: 8rem; + padding: 0 var(--default-gap-xxsmall); + padding-bottom: 2rem; + } +body [data-pane-related] { + padding: 0 var(--default-gap-xxsmall); } + body[data-pane="settings"] > section[data-pane="settings"], body[data-pane="rulesets"] > section[data-pane="rulesets"], +body[data-pane="filters"] > section[data-pane="filters"], +body[data-pane="develop"] > section[data-pane="develop"], body[data-pane="about"] > section[data-pane="about"] { display: block; } /* high dpi devices */ :root.hidpi .tabButton { - font-family: Metropolis, sans-serif; font-weight: 600; letter-spacing: 0.5px; } /* touch-screen devices */ -:root.mobile #dashboard-nav { +:root.mobile nav { flex-wrap: nowrap; overflow-x: auto; } -:root.mobile #dashboard-nav .logo { +:root.mobile nav .logo { display: none; } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/develop.css ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/develop.css --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/develop.css 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/develop.css 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,168 @@ +body[data-pane="develop"] { + height: 100vh; + } + +section[data-pane="develop"] { + display: none; + flex-grow: 1; + overflow: hidden; + } + +section[data-pane="develop"] > div { + display: flex; + flex-direction: column; + height: 100%; + } + +section[data-pane="develop"] > div > * { + margin-bottom: 0; + margin-top: 1em; + } + +#cm-container { + flex-grow: 1; + font-size: var(--monospace-size); + overflow: hidden; + } + +/* https://discuss.codemirror.net/t/how-to-set-max-height-of-the-editor/2882/2 */ +#cm-container .cm-editor { + background-color: var(--surface-0); + height: 100%; + } + +#cm-container .cm-editor .cm-line:has(.ubol-boundary) { + background-image: url('line-hor-dashed.png'), url('line-hor-dashed.png'); + background-position: left 3px, left calc(100% - 3px); + background-repeat: repeat-x; + } +#cm-container .cm-editor { + color: var(--ink-1); + } +:root.dark #cm-container .cm-editor { + color: var(--ink-2); + } +#cm-container .cm-editor .cm-line .ubol-comment { + color: #ba5300; + } +:root.dark #cm-container .cm-editor .cm-line .ubol-comment { + color: #fa7000; + } +#cm-container .cm-editor .cm-line .ubol-keyword { + color: #ae42be; + } +:root.dark #cm-container .cm-editor .cm-line .ubol-keyword { + color: #ea59ff; + } +#cm-container .cm-editor .cm-line .ubol-literal { + color: #168156; + } +:root.dark #cm-container .cm-editor .cm-line .ubol-literal { + color: #1dae74; + } +#cm-container .cm-editor .cm-line.badline:not(.cm-activeLine) { + background-color: color-mix(in srgb, var(--info3-ink) 15%, transparent 85%); + } + +#cm-container .cm-editor .cm-line .badmark { + text-decoration: underline var(--cm-negative) wavy; + text-decoration-skip-ink: none; + } + +#cm-container .cm-editor .cm-panel.cm-search { + display: flex; + flex-wrap: wrap; + font-family: sans-serif; + font-size: var(--font-size); + gap: 0.5em 1em; + padding: 0.5em 1.5em 0.5em 0.5em; + } + +#cm-container .cm-editor .cm-panel.cm-search > * { + margin: 0; + } + +#cm-container .cm-editor .cm-panel.cm-search .cm-textfield, +#cm-container .cm-editor .cm-panel.cm-search .cm-button, +#cm-container .cm-editor .cm-panel.cm-search label { + background-image: inherit; + border: inherit; + flex-grow: 0; + font-size: var(--button-font-size); + min-height: calc(var(--button-font-size) * 1.8); + } + +#cm-container .cm-editor .cm-panel .warning { + color: var(--info3-ink); + } + +#cm-container .cm-editor .cm-panel.io-panel { + background-color: var(--surface-1); + box-sizing: border-box; + display: inline-flex; + gap: 0.25em; + padding: 0.25em; + padding-inline-start: 0; + width: 100%; + } +#cm-container .cm-editor .cm-panel.io-panel button { + min-height: 30px; + } +#cm-container .cm-editor .cm-panel.io-panel button#revert { + margin-inline-end: 1em; + } +#cm-container .cm-editor .cm-panel.io-panel:not([data-io~="apply"]) button#apply { + display: none; + } +#cm-container .cm-editor .cm-panel.io-panel:not([data-io~="revert"]) button#revert { + display: none; + } +#cm-container .cm-editor .cm-panel.io-panel:not([data-io~="import"]) button#import { + display: none; + } +#cm-container .cm-editor .cm-panel.io-panel:not([data-io~="export"]) button#export { + display: none; + } + +#cm-container .cm-editor .cm-panel.info-panel { + display: flex; + flex-wrap: nowrap; + font-size: var(--font-size); + padding: var(--default-gap-xxsmall) var(--default-gap-xsmall); + } +#cm-container .cm-editor .cm-panel.info-panel .info { + flex-grow: 1; + overflow: auto; + } +#cm-container .cm-editor .cm-panel.info-panel .close { + cursor: default; + flex-shrink: 0; + padding-inline-start: 1em; + } +#cm-container .cm-editor .cm-panel.info-panel .close::after { + content: '\2715'; + } + +#cm-container .cm-editor .cm-panel.summary-panel { + background-color: color-mix(in srgb, var(--info1-ink) 15%, transparent 85%); + gap: 1em; + } +#cm-container .cm-editor .cm-panel.summary-panel .info { + flex-shrink: 0; + } + +#cm-container .cm-editor .cm-panel.feedback-panel { + background-color: color-mix(in srgb, var(--info3-ink) 15%, transparent 85%); + white-space: pre; + max-height: 10cqh; + } + +#cm-container .cm-editor .cm-gutterElement { + cursor: default; + user-select: none; + } + +#cm-container .cm-editor .cm-tooltip .badmark-tooltip { + background-color: color-mix(in srgb, var(--info3-ink) 15%, transparent 85%); + padding: var(--default-gap-xxsmall) var(--default-gap-xsmall); + } \ No newline at end of file diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/filtering-mode.css ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/filtering-mode.css --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/filtering-mode.css 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/filtering-mode.css 2025-10-25 19:32:51.000000000 +0000 @@ -1,19 +1,24 @@ +:root { + --filtering-mode-button-size: 60px; /* should be multiple of 4 */ + --filtering-mode-slider-width: calc(4 * var(--filtering-mode-button-size) + 3px); + } + .filteringModeSlider { align-items: center; + container-type: size; display: flex; - height: 60px; + height: var(--filtering-mode-button-size); justify-content: center; position: relative; - width: 240px; + width: var(--filtering-mode-slider-width); } .filteringModeButton { background-color: var(--surface-1); - box-sizing: border-box; - border-radius: 30% 15% / 15% 30%; - height: 100%; + border-radius: 20%; + height: var(--filtering-mode-button-size); position: absolute; - width: calc(25% + 2px); + width: var(--filtering-mode-button-size); z-index: 10; } @@ -22,9 +27,8 @@ border: 4px solid var(--accent-surface-1); border-radius: inherit; box-sizing: border-box; - height: calc(100% - 2px); - margin: 1px; - width: calc(100% - 2px); + height: 100%; + width: 100%; } .filteringModeSlider.moving .filteringModeButton > div, @@ -39,14 +43,12 @@ .filteringModeSlider span[data-level] { background-color: var(--accent-surface-1); - border: 1px solid var(--accent-surface-1); - box-sizing: border-box; display: inline-flex; + flex-shrink: 0; height: 30%; margin-left: 1px; - width: 25%; + width: var(--filtering-mode-button-size); } - .filteringModeSlider span[data-level]:first-of-type { margin-left: 0; } @@ -59,25 +61,33 @@ left: 0; } .filteringModeSlider[data-level="1"] .filteringModeButton { - left: calc(25% - 1px); + left: calc(var(--filtering-mode-button-size) + 1px); } .filteringModeSlider[data-level="2"] .filteringModeButton { - left: calc(50% - 1px); + left: calc(var(--filtering-mode-button-size) * 2 + 2px); } .filteringModeSlider[data-level="3"] .filteringModeButton { - left: calc(75% - 1px); + left: calc(var(--filtering-mode-button-size) * 3 + 3px); + } + +[dir="rtl"] .filteringModeSlider span[data-level] { + margin-left: 0; + margin-right: 1px; + } +[dir="rtl"] .filteringModeSlider span[data-level]:first-of-type { + margin-right: 0; } [dir="rtl"] .filteringModeSlider[data-level="0"] .filteringModeButton { - left: 75%; + right: 0; } [dir="rtl"] .filteringModeSlider[data-level="1"] .filteringModeButton { - left: 50%; + right: calc(var(--filtering-mode-button-size) + 1px); } [dir="rtl"] .filteringModeSlider[data-level="2"] .filteringModeButton { - left: 25%; + right: calc(var(--filtering-mode-button-size) * 2 + 2px); } [dir="rtl"] .filteringModeSlider[data-level="3"] .filteringModeButton { - left: 0; + right: calc(var(--filtering-mode-button-size) * 3 + 3px); } Binary files /srv/release.debian.org/tmp/En7nkbHWiS/ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/line-hor-dashed.png and /srv/release.debian.org/tmp/loyMF0iGQH/ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/line-hor-dashed.png differ diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/matched-rules.css ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/matched-rules.css --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/matched-rules.css 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/matched-rules.css 2025-10-25 19:32:51.000000000 +0000 @@ -16,6 +16,9 @@ .matchInfo:nth-of-type(2n) { background-color: lightgray; } +html.dark .matchInfo:nth-of-type(2n) { + background-color: #444; +} .requestInfo { border-inline-end: 1px dotted black; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/picker-ui.css ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/picker-ui.css --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/picker-ui.css 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/picker-ui.css 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,144 @@ +:root#ubol-picker { + --ubol-overlay-fill: rgba(255,64,64,0.10); + --ubol-overlay-border: #F00; +} + +#ubol-picker.paused svg#overlay { + cursor: not-allowed; +} + +:root aside { + background-color: var(--surface-1); + border: 1px solid var(--border-2); + max-width: min(32rem, 100vw - 4px); + min-width: min(24rem, 100vw - 4px); + row-gap: 1em; + width: min(32rem, 100vw - 4px); +} + +#ubol-picker aside > section:last-of-type { + margin-block-end: 0; +} +#ubol-picker aside > section:not(#windowbar,#moreOrLess) { + padding: 0 4px; +} + +#ubol-picker[data-view="0"] aside section[data-view="1"], +#ubol-picker[data-view="0"] aside section[data-view="2"] { + display: none; +} +#ubol-picker[data-view="1"] aside section[data-view="2"] { + display: none; +} + +#ubol-picker:not(.paused) aside > section:not(#windowbar) { + display: none; +} + +#ubol-picker textarea { + border: 0; + box-sizing: border-box; + min-height: 5em; + resize: none; + width: 100%; +} +#ubol-picker.mobile textarea { + height: unset; +} +#ubol-picker .resultsetWidgets { + color: var(--ink-2); + display: flex; + flex-direction: column; + font-size: small; + gap: 0.25em; +} +#ubol-picker .resultsetWidgets > span:first-of-type { + display: flex; + margin: 0 1em; +} +#ubol-picker .resultsetWidgets label { + flex-grow: 1; +} +#ubol-picker .resultsetWidgets #resultsetCount { + display: inline-block; + text-align: right; + width: 8ch; +} + +#ubol-picker #toolbar { + display: flex; + justify-content: space-between; +} +#ubol-picker #toolbar button { + min-width: 5em; +} + +#ubol-picker #candidateFilters { + font-family: monospace; + font-size: small; + max-height: min(20em, 30vh); + min-height: 6em; + overflow-y: auto; + word-break: break-all; +} +#ubol-picker #candidateFilters ul { + margin: 0; + padding-inline-start: calc(2ch + 4px); + user-select: none; + -webkit-user-select: none; +} +#ubol-picker #candidateFilters ul > li { + list-style-type: '\25A0\00A0'; +} +#ubol-picker #candidateFilters ul >li:has(:not(span.on)) { + list-style-type: '\25A1\00A0'; +} +#ubol-picker #candidateFilters ul > li:nth-of-type(2n+1) { + background-color: var(--surface-2); +} +#ubol-picker #candidateFilters ul > li > span { + border: 1px solid transparent; + padding: 1px 2px; +} +#ubol-picker #candidateFilters ul > li > span.on { + background-color: var(--accent-surface-1); + color: var(--accent-ink-1);} +#ubol-picker #candidateFilters ul > li > span:hover { + border: 1px solid var(--ink-1); +} + +#ubol-picker #moreOrLess { + color: var(--ink-2); + column-gap: 0; + display: grid; + font-size: small; + grid-template: auto / 1fr 1fr; + justify-items: stretch; + user-select: none; + -webkit-user-select: none; + white-space: nowrap; +} +#ubol-picker #moreOrLess > span { + cursor: pointer; + padding: var(--default-gap-xxsmall) var(--default-gap-xsmall); +} +#ubol-picker #moreOrLess > span:last-of-type { + text-align: end; +} +#ubol-picker[data-view="2"] aside #moreOrLess > span:first-of-type { + visibility: hidden; +} +#ubol-picker[data-view="0"] aside #moreOrLess > span:last-of-type { + visibility: hidden; +} +#ubol-picker.desktop aside #moreOrLess > span:hover { + background-color: var(--surface-2); +} + +#ubol-picker.preview #toolbar #preview { + color: var(--accent-ink-1); + background-color: var(--accent-surface-1); +} +#ubol-picker.preview #overlay path { + display: none; +} diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/popup.css ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/popup.css --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/popup.css 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/popup.css 2025-10-25 19:32:51.000000000 +0000 @@ -2,49 +2,45 @@ .fa-icon.fa-icon-badged > .fa-icon-badge { bottom: auto; top: -20%; - } +} + +:root { + --popup-min-width: calc( + var(--filtering-mode-slider-width) + + var(--filtering-mode-button-size) / 2 + ); +} :root body, :root.mobile body { - --font-size: 14px; --popup-gap: var(--font-size); --popup-gap-thin: calc(0.5 * var(--popup-gap)); --popup-gap-extra-thin: calc(0.25 * var(--popup-gap)); - --popup-main-min-width: 18em; - --popup-firewall-min-width: 30em; - --popup-rule-cell-width: 5em; - font-size: var(--font-size); - line-height: 20px; - min-width: 100%; - } + min-width: var(--popup-min-width); +} :root body.loading { - opacity: 0; - } + visibility: hidden; +} a { color: var(--ink-1); fill: var(--ink-1); text-decoration: none; - } +} :focus { outline: 0; - } +} #main { align-self: flex-start; display: flex; flex-direction: column; - max-width: 340px; - min-width: 100%; - } +} :root.portrait #main { align-self: inherit; - } +} hr { - border: 0; - border-top: 1px solid var(--hr-ink); - margin: 0; - padding: 0; - } + margin: 0.5em 0; +} #hostname { align-items: center; @@ -55,229 +51,147 @@ padding: 0 var(--popup-gap-extra-thin); text-align: center; word-break: break-all; - } +} #hostname > span { word-break: break-all; - } +} #hostname > span + span { font-weight: 600; - } +} body[data-forbid~="filteringMode"] .filteringModeSlider { pointer-events: none; - } -body[data-forbid~="dashboard"] #gotoDashboard { +} +body[data-forbid~="zapper"] #gotoZapper, +body[data-forbid~="picker"] #gotoPicker, +body[data-forbid~="picker"] #gotoUnpicker, +body[data-forbid~="report"] #gotoReport, +body[data-forbid~="zapper"][data-forbid~="picker"][data-forbid~="report"] .localTools { display: none; - } +} +body[data-forbid~="dashboard"] .globalTools { + display: none; +} #filteringModeText { color: var(--ink-3); - margin: var(--default-gap-small); - margin-top: 0; + margin-bottom: var(--popup-gap-thin); text-align: center; text-transform: lowercase; - } +} #filteringModeText > span { color: var(--accent-surface-1); - } +} #filteringModeText > span:nth-of-type(2) { display: none; - } +} #filteringModeText > span:nth-of-type(2):not(:empty) { display: inline; - } +} #filteringModeText > span:nth-of-type(2):not(:empty)::before { content: '\2002\2192\2002'; - } +} [dir="rtl"] #filteringModeText > span:nth-of-type(2):not(:empty)::before { content: '\2002\2190\2002'; - } +} .filteringModeSlider { align-self: center; - margin: var(--popup-gap); - width: calc(var(--popup-main-min-width) - 1em); - } - -.rulesetTools { - background-color: transparent; - border: 0; - box-sizing: border-box; - display: flex; - flex-direction: column; - justify-content: space-evenly; - width: 25%; - } -.rulesetTools [id] { - background-color: var(--popup-ruleset-tool-surface); - border-radius: 4px; - cursor: pointer; - fill: var(--popup-ruleset-tool-ink); - flex-grow: 1; - font-size: 2.2em; - padding: 0; - visibility: hidden; - } -.rulesetTools [id]:not(:first-of-type) { - margin-block-start: 1px; - } -.rulesetTools [id] > svg { - fill: var(--ink-4); - } + margin: var(--popup-gap) 0; +} + body.needReload #refresh { visibility: visible; - } +} -#rulesetStats { - padding: 0 var(--popup-gap-thin); - } -#rulesetStats .rulesetDetails h1 { - font-size: 1em; - font-weight: normal; - margin: 0.5em 0 0.25em 0; - } -#rulesetStats .rulesetDetails p { +.toolMenu { + border-top: 1px solid var(--surface-2); + display: flex; + flex-direction: column; + margin: 0.5em 0; + padding-top: 0.5em; +} +:root:not(.isHTTP) .needHTTP { + display: none; +} +.toolMenu > label { + font-size: 90%; color: var(--ink-2); - font-size: var(--font-size-smaller); - margin: 0.25em 0 0.5em 0.5em; - } - -.itemRibbon { - column-gap: var(--popup-gap); - display: grid; - grid-auto-columns: 1fr; - grid-auto-flow: column; - grid-template: auto / 1fr 1fr; - margin: var(--popup-gap); - } -.itemRibbon > span + span { - text-align: end; - } + line-height: calc(var(--font-size) * 1.8); + margin-inline-start: 0.5em; +} +.toolMenu > .tool { + cursor: pointer; + display: flex; + padding: 0.5em 0.5em 0.5em 0; + unicode-bidi: embed; +} +.toolMenu > .tool:hover { + color: var(--ink-1); + fill: var(--ink-1); +} +.toolMenu > .tool:not(.enabled) { + display: none; +} +.toolMenu > .tool .fa-icon { + font-size: 1.4em; + min-width: 1.4em; +} +.toolMenu > .tool [data-i18n] { + flex-grow: 1; +} .toolRibbon { - align-items: center; background-color: var(--popup-toolbar-surface); - display: grid; - grid-auto-columns: 1fr; - grid-auto-flow: column; - grid-template: auto / repeat(5, 1fr); - justify-items: center; + display: flex; + flex-wrap: nowrap; + justify-content: space-between; + margin: 0; white-space: normal; - } +} .toolRibbon .tool { cursor: pointer; display: flex; flex-direction: column; - font-size: 1.4em; min-width: 32px; - padding: var(--popup-gap) - var(--popup-gap-thin); + padding: var(--default-gap-small); unicode-bidi: embed; visibility: hidden; - } +} .toolRibbon .tool:hover { color: var(--ink-1); fill: var(--ink-1); - } +} .toolRibbon .tool.enabled { visibility: visible; - } +} +.toolRibbon .tool.fa-icon { + font-size: 1.4em; +} +:root.mobile .toolRibbon .tool.fa-icon { + font-size: 1.6em; +} .toolRibbon .tool .caption { font: 10px/12px sans-serif; margin-top: 6px; text-align: center; - } -body.mobile.no-tooltips .toolRibbon .tool { - font-size: 1.6em; - } -.toolRibbon.genericTools { - margin-bottom: 0; - } - -#moreOrLess { - column-gap: 0; - display: grid; - grid-template: auto / 1fr 1fr; - justify-items: stretch; - margin: 1px 0 0 0; - } -#moreOrLess > span { - cursor: pointer; - margin: 0; - padding: var(--popup-gap-thin) var(--popup-gap); - user-select: none; - white-space: nowrap; - } -#moreButton .fa-icon { - transform: rotate(180deg); - } -#lessButton { - border-inline-start: 1px solid var(--surface-1); - text-align: end; - } -body[data-section="a b"] #moreButton { - pointer-events: none; - visibility: hidden; - } -body[data-section=""] #lessButton { - pointer-events: none; - visibility: hidden; - } -body:not([data-section~="a"]) [data-section="a"] { - display: none; - } -body:not([data-section~="b"]) [data-section="b"] { +} +:root:not(.mobile) .toolRibbon .caption { display: none; - } - -/* configurable UI elements */ -:root:not(.mobile) .toolRibbon .caption, -:root.mobile body.no-tooltips .toolRibbon .caption, -:root.mobile body[data-ui~="-captions"] .toolRibbon .caption { - display: none; - } -:root.mobile .toolRibbon .caption, -:root:not(.mobile) body[data-ui~="+captions"] .toolRibbon .caption { - display: inherit; - } -:root:not(.mobile) .toolRibbon .tool, -:root.mobile body.no-tooltips .toolRibbon .tool, -:root.mobile body[data-ui~="-captions"] .toolRibbon .tool { - padding: var(--popup-gap) var(--popup-gap-thin); - } -:root.mobile #moreOrLess > span { - padding: var(--popup-gap); - } +} /* horizontally-constrained viewport */ :root.portrait body { overflow-y: auto; width: 100%; - } +} :root.portrait #main { max-width: unset; - } +} /* mouse-driven devices */ :root.desktop { display: flex; - } -:root.desktop body { - --popup-gap: calc(var(--font-size) * 0.875); - } -:root.desktop .rulesetTools [id]:hover { - background-color: var(--popup-ruleset-tool-surface-hover); - } -:root.desktop .rulesetTools [id]:hover > svg { - fill: var(--ink-2); - } +} :root.desktop .tool:hover { background-color: var(--popup-toolbar-surface-hover); - } -:root.desktop #moreOrLess > span:hover { - background-color: var(--surface-2); - /* background-color: var(--popup-toolbar-surface-hover); */ - } - -#templates { - display: none; - } +} diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/report.css ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/report.css --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/report.css 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/report.css 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,3 @@ +.warning { + color: var(--info2-ink); +} \ No newline at end of file diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/settings.css ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/settings.css --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/settings.css 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/settings.css 2025-10-25 19:32:51.000000000 +0000 @@ -1,19 +1,14 @@ -body.loading { - visibility: hidden; - } -body .firstRun { - display: none; - } -body.firstRun .firstRun { - background-color: rgb(var(--dashboard-highlight-surface-rgb)); - display: block; - padding: 8px; +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } } -body .firstRun > *:first-child { - margin-top: 0; + +:root { + --filtering-mode-button-size: 32px; } -body .firstRun > *:last-child { - margin-bottom: 0; + +body.loading { + visibility: hidden; } h3 { margin: 1em 0; @@ -35,6 +30,9 @@ body[data-forbid~="filteringMode"] section[data-pane="settings"] > div:has(> h3[data-i18n="filteringMode0Name"]) { display: none; } +body[data-forbid~="develop"] #developerMode { + display: none; + } label:has(input[type="checkbox"][disabled]), label:has(input[type="checkbox"][disabled]) + legend { @@ -81,28 +79,35 @@ white-space: pre-line; } .filteringModeSlider { - height: calc(60px / 2); pointer-events: none; - width: calc(240px / 2); } h3[data-i18n="filteringMode0Name"]::first-letter { text-transform: capitalize; } -#trustedSites { - box-sizing: border-box; - height: 6rem; - resize: vertical; - width: 100%; + +body[data-platform="safari"] [data-platform-exclude="safari"] { + display: none; } -section[data-pane="rulesets"] > div:first-of-type { - background-color: var(--surface-1); - flex-shrink: 0; - padding: 1em 0; - position: sticky; - top: 0; - z-index: 10; +section[data-pane="settings"] p:has(button) { + display: flex; + flex-wrap: wrap; + gap: 1em; + } + +body:not(.committing) #commit-spinner { + display: none; + } +body.committing #commit-spinner { + animation: spin 1s steps(8) infinite; + fill: var(--accent-surface-1); + } +#dnrError { + color: var(--info3-ink); + } +#dnrError:empty { + display: none; } section[data-pane="rulesets"] > div:first-of-type > p:first-of-type { margin-top: 0; @@ -228,9 +233,105 @@ margin-top: 0.2em; } -#templates { +body section[data-pane="filters"] { + padding-inline: 0; + } +body section[data-pane="filters"] .hostnames { + border-bottom: 1px solid var(--border-1); + margin-block-start: 1em; + } +body section[data-pane="filters"] .hostnames:empty { + display: none; + } +body.busy section[data-pane="filters"] .hostnames { + pointer-events: none; + } +section[data-pane="filters"] ul { + list-style: none; + margin: 0; + padding-inline-start: 0; + } +section[data-pane="filters"] .hostnames > li.hostname > div { + background-color: var(--surface-2); + padding-inline-start: 0.5em; + } +section[data-pane="filters"] ul ul { + padding-block-end: 1em; + padding-inline-start: 0.5em; + } +section[data-pane="filters"] li > div { + display: flex; + padding-block: 4px; + } +section[data-pane="filters"] li [contenteditable] { + flex-grow: 1; + word-break: break-all; + } +section[data-pane="filters"] li [contenteditable]:focus { + background-color: var(--surface-0); + } +section[data-pane="filters"] li .fa-icon { + align-self: baseline; + font-size: calc(var(--font-size) + 2px); + padding: 0 0.5em; + top: 2px; + } +section[data-pane="filters"] li.selector:not(:first-of-type) { + border-top: 1px dotted var(--border-1); + } +section[data-pane="filters"] li.hostname:not(:has(li.selector:not(.removed))) > div [contenteditable], +section[data-pane="filters"] li.selector.removed [contenteditable] { + color: red; + text-decoration-line: line-through; + } +section[data-pane="filters"] li.hostname:not(:has(li.selector:not(.removed))) > div span.remove, +section[data-pane="filters"] li.selector.removed > div span.remove, +section[data-pane="filters"] li.hostname:has(li.selector:not(.removed)) > div span.undo, +section[data-pane="filters"] li.selector:not(.removed) > div span.undo { + display: none; + } +html.desktop section[data-pane="filters"] li > div:hover { + background-color: var(--surface-0); + } +html.desktop section[data-pane="filters"] li > div span.fa-icon:hover { + transform: scale(1.3); + } +section[data-pane="filters"] aside { + padding: 1em 0.5em; + } +section[data-pane="filters"] aside details { + padding: 0; + } +section[data-pane="filters"] aside summary { + cursor: default; + line-height: 2; + } +section[data-pane="filters"] aside .importFromText { + color: var(--ink-2); + } +section[data-pane="filters"] aside .importFromText textarea { + background-color: var(--surface-1); + border: 1px solid var(--border-1); + box-sizing: border-box; + min-height: 6em; + resize: vertical; + width: 100%; + } +section[data-pane="filters"] aside .importFromText textarea:focus { + background-color: var(--surface-0); + } +section[data-pane="filters"] aside .importFromText:has(textarea:placeholder-shown) button:has([data-i18n="addButton"]) { + display: none; + } +section[data-pane="filters"] aside .importFromText:not(:has(textarea:placeholder-shown)) button:has([data-i18n="importAndAppendButton"]), +section[data-pane="filters"] aside .importFromText:not(:has(textarea:placeholder-shown)) button:has([data-i18n="exportButton"]) { display: none; } +section[data-pane="filters"] aside p { + display: flex; + flex-wrap: wrap; + gap: 1em; + } @media (max-width: 480px) { #defaultFilteringMode { diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/tool-overlay-ui.css ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/tool-overlay-ui.css --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/tool-overlay-ui.css 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/tool-overlay-ui.css 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,99 @@ +:root { + --ubol-overlay-fill: rgba(255,255,255,0.2); + --ubol-overlay-border: #FFF; + --ubol-overlay-canvas: rgba(128,128,128,0.3); +} +:root.dark aside { + color-scheme: dark; +} + +:root, +:root > body { + background: transparent; + height: 100vh; + height: 100svh; + margin: 0; + overflow: hidden; + width: 100vw; +} +:root > body.loading { + visibility: hidden; +} + +:root :focus { + outline: none; +} + +svg#overlay { + cursor: crosshair; + box-sizing: border-box; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +svg#overlay > path:first-child { + fill: var(--ubol-overlay-canvas); + fill-rule: evenodd; +} +svg#overlay > path + path { + stroke: var(--ubol-overlay-border); + stroke-width: 1.5px; + fill: var(--ubol-overlay-fill); +} + +:root aside { + box-sizing: border-box; + cursor: default; + display: flex; + flex-direction: column; + position: fixed; + z-index: 100; +} +:root body[dir="rtl"] aside { + left: 2px; + right: unset; +} + +:root.minimized aside > section:not(#windowbar) { + display: none !important; +} +:root.minimized aside { + min-width: min(12em, 100vw - 4px); + width: min(12em, 100vw - 4px); +} + +:root aside #windowbar { + border-bottom: 1px solid var(--border-1); + display: flex; +} +:root aside #windowbar > div { + fill: none; + height: 2em; + stroke: var(--ink-1); + stroke-width: 2px; + width: 2em; +} +:root.minimized aside #windowbar > div { + height: 3em; + width: 3em; +} +:root.minimized aside #windowbar > #minimize svg > path, +#windowbar #minimize svg > rect { + display: none; +} +:root.minimized aside #windowbar > #minimize svg > rect { + display: initial; +} +:root #windowbar > #move { + align-items: center; + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAYAAACtBE5DAAAAFElEQVQI12NgwAfKy8v/M5ANYLoBshgEyQo6H9UAAAAASUVORK5CYII='); + cursor: grab; + display: flex; + justify-content: center; + flex-grow: 1; +} +:root #windowbar > div:hover { + background-color: var(--surface-2) +} diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/unpicker-ui.css ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/unpicker-ui.css --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/unpicker-ui.css 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/unpicker-ui.css 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,64 @@ +:root#ubol-unpicker { + --ubol-overlay-fill: rgba(64,255,64,0.10); + --ubol-overlay-border: #0F0; +} + +#ubol-unpicker svg#overlay { + cursor: not-allowed; +} + +:root aside { + background-color: var(--surface-1); + border: 1px solid var(--border-2); + max-height: 40vh; + max-width: min(32rem, 100vw - 4px); + min-width: min(24rem, 100vw - 4px); + width: min(32rem, 100vw - 4px); +} + +#ubol-unpicker aside > section:not(#windowbar) { + margin: 1em 1em 0 1em; +} +#ubol-unpicker aside > section:not(#windowbar):last-of-type { + margin-bottom: 1em; +} +#ubol-unpicker aside > section [data-i18n="unpickerUsage"] { + color: var(--ink-2); + font-size: small; +} + +#ubol-unpicker #customFilters { + font-family: monospace; + overflow: auto; +} +#ubol-unpicker .customFilter { + display: flex; +} +#ubol-unpicker .customFilter:nth-of-type(2n+1) { + background-color: var(--surface-2); +} +#ubol-unpicker .customFilter > span.selector { + flex-grow: 1; + font-size: small; + padding: 0.5em; +} +#ubol-unpicker .customFilter.on > span.selector { + background-color: var(--accent-surface-1); + color: var(--accent-ink-1); +} +#ubol-unpicker .customFilter.removed > span.remove { + display: none; +} +#ubol-unpicker .customFilter.removed > span.selector { + color: red; + pointer-events: none; + text-decoration-line: line-through; +} +#ubol-unpicker .customFilter > span.fa-icon { + flex-shrink: 0; + font-size: 1.25em; + padding: 0 0.5em; +} +#ubol-unpicker .customFilter:not(.removed) > span.undo { + display: none; +} diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/zapper-ui.css ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/zapper-ui.css --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/css/zapper-ui.css 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/css/zapper-ui.css 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,29 @@ +:root#ubol-zapper { + --quit-button-size: max(4em, min(6em, calc(100vw / 8), calc(100vh / 8))); + --ubol-overlay-fill: rgba(255,255,63,0.10); + --ubol-overlay-border: #FF0; +} + +#ubol-zapper aside { + gap: 2px; + right: 2px; + top: 50%; + transform: translateY(-50%); +} + +#ubol-zapper aside > div { + background-color: var(--surface-1); + border: 1px solid rgba(0,0,0,0.5); + box-sizing: border-box; + fill: none; + stroke: var(--ink-1); + stroke-width: 2px; + width: var(--quit-button-size); + height: var(--quit-button-size); +} +#ubol-zapper aside > div:hover { + background-color: var(--surface-2) +} +:root:not(.mobile) #pick { + display: none; +} \ No newline at end of file diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/dashboard.html ublock-origin-1.67.0+dfsg/platform/mv3/extension/dashboard.html --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/dashboard.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/dashboard.html 2025-10-25 19:32:51.000000000 +0000 @@ -3,6 +3,7 @@ + @@ -12,33 +13,32 @@ + - + -
- -
+
+ + +
+

spinner

+

+

+
+
-

-

-

-

-

- -
-

-

-
- -

@@ -88,24 +88,58 @@
-

-

-
-

-

_

-

+

+

+

+

+

+

+

+
+

_

+

_

+

+ +

+
+
+ +
+
    + +
    + +
    -

    -

    +

    +   +

    +
    -
    @@ -114,7 +148,7 @@
    Copyright (c) Raymond Hill 2014-present
    -
    +
    @@ -125,17 +159,20 @@
    +
    +
    +
    
    +            
    -
    -
    + + + + + + + + + + + + + + Binary files /srv/release.debian.org/tmp/En7nkbHWiS/ublock-origin-1.62.0+dfsg/platform/mv3/extension/img/icon_128_off.png and /srv/release.debian.org/tmp/loyMF0iGQH/ublock-origin-1.67.0+dfsg/platform/mv3/extension/img/icon_128_off.png differ Binary files /srv/release.debian.org/tmp/En7nkbHWiS/ublock-origin-1.62.0+dfsg/platform/mv3/extension/img/icon_16_off.png and /srv/release.debian.org/tmp/loyMF0iGQH/ublock-origin-1.67.0+dfsg/platform/mv3/extension/img/icon_16_off.png differ Binary files /srv/release.debian.org/tmp/En7nkbHWiS/ublock-origin-1.62.0+dfsg/platform/mv3/extension/img/icon_32_off.png and /srv/release.debian.org/tmp/loyMF0iGQH/ublock-origin-1.67.0+dfsg/platform/mv3/extension/img/icon_32_off.png differ Binary files /srv/release.debian.org/tmp/En7nkbHWiS/ublock-origin-1.62.0+dfsg/platform/mv3/extension/img/icon_512.png and /srv/release.debian.org/tmp/loyMF0iGQH/ublock-origin-1.67.0+dfsg/platform/mv3/extension/img/icon_512.png differ Binary files /srv/release.debian.org/tmp/En7nkbHWiS/ublock-origin-1.62.0+dfsg/platform/mv3/extension/img/icon_64_off.png and /srv/release.debian.org/tmp/loyMF0iGQH/ublock-origin-1.67.0+dfsg/platform/mv3/extension/img/icon_64_off.png differ diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/action.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/action.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/action.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/action.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,110 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2022-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { matchesFromHostnames, strArrayEq } from './utils.js'; +import { browser } from './ext.js'; + +/******************************************************************************/ + +let reverseMode = false; + +/******************************************************************************/ + +function disableToolbarIcon(tabId) { + const details = { + path: { + '16': '/img/icon_16_off.png', + '32': '/img/icon_32_off.png', + '64': '/img/icon_64_off.png', + '128': '/img/icon_128_off.png', + } + }; + if ( tabId !== undefined ) { + details.tabId = tabId; + } + browser.action.setIcon(details); +} + +function enableToolbarIcon(tabId) { + const details = { + path: { + '16': '/img/icon_16.png', + '32': '/img/icon_32.png', + '64': '/img/icon_64.png', + '128': '/img/icon_128.png', + } + }; + if ( tabId !== undefined ) { + details.tabId = tabId; + } + browser.action.setIcon(details); +} + +/******************************************************************************/ + +export function toggleToolbarIcon(tabId) { + if ( reverseMode ) { + enableToolbarIcon(tabId); + } else { + disableToolbarIcon(tabId); + } +} + +/******************************************************************************/ + +// https://github.com/uBlockOrigin/uBOL-home/issues/198 +// Ensure the toolbar icon reflects the no-filtering mode of "trusted sites" + +export async function registerToolbarIconToggler(context) { + const { none, basic, optimal, complete } = context.filteringModeDetails; + const reverseModeAfter = none.delete('all-urls'); + const toToggle = reverseModeAfter ? + new Set([ ...basic, ...optimal, ...complete ]) + : none; + + if ( reverseModeAfter !== reverseMode ) { + if ( reverseModeAfter ) { + disableToolbarIcon(); + } else { + enableToolbarIcon(); + } + reverseMode = reverseModeAfter; + } + + if ( toToggle.size === 0 ) { return; } + + const registered = context.before.get('toolbar-icon'); + context.before.delete('toolbar-icon'); // Important! + + const directive = { + id: 'toolbar-icon', + js: [ '/js/scripting/toolbar-icon.js' ], + matches: matchesFromHostnames(toToggle), + runAt: 'document_start', + }; + + if ( registered === undefined ) { + context.toAdd.push(directive); + } else if ( strArrayEq(registered.matches, directive.matches) === false ) { + context.toRemove.push('toolbar-icon'); + context.toAdd.push(directive); + } +} diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/admin.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/admin.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/admin.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/admin.js 2025-10-25 19:32:51.000000000 +0000 @@ -21,33 +21,89 @@ import { adminRead, - localRead, localWrite, + localRead, localRemove, localWrite, sessionRead, sessionWrite, } from './ext.js'; import { enableRulesets, getRulesetDetails, + setStrictBlockMode, } from './ruleset-manager.js'; import { - getTrustedSites, + getDefaultFilteringMode, readFilteringModeDetails, } from './mode-manager.js'; +import { + rulesetConfig, + saveRulesetConfig, +} from './config.js'; + import { broadcastMessage } from './utils.js'; -import { dnr } from './ext.js'; +import { dnr } from './ext-compat.js'; import { registerInjectables } from './scripting-manager.js'; -import { rulesetConfig } from './config.js'; import { ubolLog } from './debug.js'; /******************************************************************************/ +export async function loadAdminConfig() { + const [ + showBlockedCount, + strictBlockMode, + ] = await Promise.all([ + adminReadEx('showBlockedCount'), + adminReadEx('strictBlockMode'), + ]); + applyAdminConfig({ showBlockedCount, strictBlockMode }); +} + +/******************************************************************************/ + +function applyAdminConfig(config, apply = false) { + const toApply = []; + for ( const [ key, val ] of Object.entries(config) ) { + if ( typeof val !== typeof rulesetConfig[key] ) { continue; } + if ( val === rulesetConfig[key] ) { continue; } + rulesetConfig[key] = val; + toApply.push(key); + } + if ( toApply.length === 0 ) { return; } + saveRulesetConfig(); + if ( apply !== true ) { return; } + while ( toApply.length !== 0 ) { + const key = toApply.pop(); + switch ( key ) { + case 'showBlockedCount': { + if ( typeof dnr.setExtensionActionOptions !== 'function' ) { break; } + const { showBlockedCount } = config; + dnr.setExtensionActionOptions({ + displayActionCountAsBadgeText: showBlockedCount, + }); + broadcastMessage({ showBlockedCount }); + break; + } + case 'strictBlockMode': { + const { strictBlockMode } = config; + setStrictBlockMode(strictBlockMode, true).then(( ) => { + broadcastMessage({ strictBlockMode }); + }); + break; + } + default: + break; + } + } +} + +/******************************************************************************/ + const adminSettings = { - keys: new Set(), + keys: new Map(), timer: undefined, - change(key) { - this.keys.add(key); + change(key, value) { + this.keys.set(key, value); if ( this.timer !== undefined ) { return; } this.timer = self.setTimeout(( ) => { this.timer = undefined; @@ -66,11 +122,27 @@ const [ adminRulesets, enabledRulesets ] = results; broadcastMessage({ adminRulesets, enabledRulesets }); } + if ( this.keys.has('defaultFiltering') ) { + ubolLog('admin setting "defaultFiltering" changed'); + await readFilteringModeDetails(true); + await registerInjectables(); + const defaultFilteringMode = await getDefaultFilteringMode(); + broadcastMessage({ defaultFilteringMode }); + } if ( this.keys.has('noFiltering') ) { ubolLog('admin setting "noFiltering" changed'); - await readFilteringModeDetails(true); - const trustedSites = await getTrustedSites(); - broadcastMessage({ trustedSites: Array.from(trustedSites) }); + const filteringModeDetails = await readFilteringModeDetails(true); + broadcastMessage({ filteringModeDetails }); + } + if ( this.keys.has('showBlockedCount') ) { + ubolLog('admin setting "showBlockedCount" changed'); + const showBlockedCount = this.keys.get('showBlockedCount'); + applyAdminConfig({ showBlockedCount }, true); + } + if ( this.keys.has('strictBlockMode') ) { + ubolLog('admin setting "strictBlockMode" changed'); + const strictBlockMode = this.keys.get('strictBlockMode'); + applyAdminConfig({ strictBlockMode }, true); } this.keys.clear(); } @@ -79,11 +151,32 @@ /******************************************************************************/ export async function getAdminRulesets() { - const adminList = await adminReadEx('rulesets'); + const [ + adminList, + rulesetDetails, + ] = await Promise.all([ + adminReadEx('rulesets'), + getRulesetDetails(), + ]); const adminRulesets = new Set(Array.isArray(adminList) && adminList || []); + if ( adminRulesets.has('-default') ) { + adminRulesets.delete('-default'); + for ( const ruleset of rulesetDetails.values() ) { + if ( ruleset.enabled !== true ) { continue; } + if ( adminRulesets.has(`+${ruleset.id}`) ) { continue; } + adminRulesets.add(`-${ruleset.id}`); + } + } + if ( adminRulesets.has('+default') ) { + adminRulesets.delete('+default'); + for ( const ruleset of rulesetDetails.values() ) { + if ( ruleset.enabled !== true ) { continue; } + if ( adminRulesets.has(`-${ruleset.id}`) ) { continue; } + adminRulesets.add(`+${ruleset.id}`); + } + } if ( adminRulesets.has('-*') ) { adminRulesets.delete('-*'); - const rulesetDetails = await getRulesetDetails(); for ( const ruleset of rulesetDetails.values() ) { if ( ruleset.enabled ) { continue; } if ( adminRulesets.has(`+${ruleset.id}`) ) { continue; } @@ -97,23 +190,24 @@ export async function adminReadEx(key) { let cacheValue; - const session = await sessionRead(`admin_${key}`); + const session = await sessionRead(`admin.${key}`); if ( session ) { cacheValue = session.data; } else { - const local = await localRead(`admin_${key}`); + const local = await localRead(`admin.${key}`); if ( local ) { cacheValue = local.data; } + localRemove(`admin_${key}`); // TODO: remove eventually } adminRead(key).then(async value => { - const adminKey = `admin_${key}`; + const adminKey = `admin.${key}`; await Promise.all([ sessionWrite(adminKey, { data: value }), localWrite(adminKey, { data: value }), ]); if ( JSON.stringify(value) === JSON.stringify(cacheValue) ) { return; } - adminSettings.change(key); + adminSettings.change(key, value); }); return cacheValue; } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/background.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/background.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/background.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/background.js 2025-10-25 19:32:51.000000000 +0000 @@ -22,63 +22,92 @@ import { MODE_BASIC, MODE_OPTIMAL, + defaultFilteringModes, getDefaultFilteringMode, getFilteringMode, - getTrustedSites, + getFilteringModeDetails, setDefaultFilteringMode, setFilteringMode, - setTrustedSites, + setFilteringModeDetails, syncWithBrowserPermissions, } from './mode-manager.js'; import { - adminRead, + addCustomFilters, + customFiltersFromHostname, + getAllCustomFilters, + hasCustomFilters, + injectCustomFilters, + removeAllCustomFilters, + removeCustomFilters, + startCustomFilters, + terminateCustomFilters, +} from './filter-manager.js'; + +import { + adminReadEx, + getAdminRulesets, + loadAdminConfig, +} from './admin.js'; + +import { + broadcastMessage, + gotoURL, + hasBroadHostPermissions, + hostnamesFromMatches, +} from './utils.js'; + +import { browser, - dnr, localRead, localRemove, localWrite, runtime, - windows, + webextFlavor, } from './ext.js'; import { - adminReadEx, - getAdminRulesets, -} from './admin.js'; + defaultConfig, + loadRulesetConfig, + process, + rulesetConfig, + saveRulesetConfig, +} from './config.js'; import { enableRulesets, excludeFromStrictBlock, - getEnabledRulesetsDetails, + getDefaultRulesetsFromEnv, + getEffectiveDynamicRules, + getEffectiveSessionRules, + getEffectiveUserRules, getRulesetDetails, patchDefaultRulesets, setStrictBlockMode, updateDynamicRules, updateSessionRules, + updateUserRules, } from './ruleset-manager.js'; import { + getConsoleOutput, getMatchedRules, isSideloaded, toggleDeveloperMode, + ubolErr, ubolLog, } from './debug.js'; -import { - loadRulesetConfig, - process, - rulesetConfig, - saveRulesetConfig, -} from './config.js'; - -import { broadcastMessage } from './utils.js'; +import { dnr } from './ext-compat.js'; import { registerInjectables } from './scripting-manager.js'; +import { toggleToolbarIcon } from './action.js'; /******************************************************************************/ -const UBOL_ORIGIN = runtime.getURL('').replace(/\/$/, ''); +const UBOL_ORIGIN = runtime.getURL('').replace(/\/$/, '').toLowerCase(); const canShowBlockedCount = typeof dnr.setExtensionActionOptions === 'function'; +let pendingPermissionRequest; + /******************************************************************************/ function getCurrentVersion() { @@ -87,87 +116,133 @@ /******************************************************************************/ -async function hasGreatPowers(origin) { - if ( /^https?:\/\//.test(origin) === false ) { return false; } - return browser.permissions.contains({ - origins: [ `${origin}/*` ], - }); -} - -async function hasOmnipotence() { - const manifest = runtime.getManifest(); - const hasOmnipotence = Array.isArray(manifest.host_permissions) && - manifest.host_permissions.includes(''); - if ( hasOmnipotence ) { return true; } - return browser.permissions.contains({ - origins: [ '' ], - }); -} - async function onPermissionsRemoved() { - const beforeMode = await getDefaultFilteringMode(); const modified = await syncWithBrowserPermissions(); if ( modified === false ) { return false; } - const afterMode = await getDefaultFilteringMode(); - if ( beforeMode > MODE_BASIC && afterMode <= MODE_BASIC ) { - updateDynamicRules(); - } registerInjectables(); return true; } -/******************************************************************************/ - -async function gotoURL(url, type) { - const pageURL = new URL(url, runtime.getURL('/')); - const tabs = await browser.tabs.query({ - url: pageURL.href, - windowType: type !== 'popup' ? 'normal' : 'popup' - }); - - if ( Array.isArray(tabs) && tabs.length !== 0 ) { - const { windowId, id } = tabs[0]; +// https://github.com/uBlockOrigin/uBOL-home/issues/280 +async function onPermissionsAdded(permissions) { + const details = pendingPermissionRequest; + pendingPermissionRequest = undefined; + if ( details === undefined ) { + const modified = await syncWithBrowserPermissions(); + if ( modified === false ) { return; } return Promise.all([ - browser.windows.update(windowId, { focused: true }), - browser.tabs.update(id, { active: true }), + updateSessionRules(), + registerInjectables(), ]); } - - if ( type === 'popup' ) { - return windows.create({ - type: 'popup', - url: pageURL.href, - }); + const defaultMode = await getDefaultFilteringMode(); + if ( defaultMode >= MODE_OPTIMAL ) { return; } + if ( Array.isArray(permissions.origins) === false ) { return; } + const hostnames = hostnamesFromMatches(permissions.origins); + if ( hostnames.includes(details.hostname) === false ) { return; } + const beforeLevel = await getFilteringMode(details.hostname); + if ( beforeLevel === details.afterLevel ) { return; } + const afterLevel = await setFilteringMode(details.hostname, details.afterLevel); + if ( afterLevel !== details.afterLevel ) { return; } + await registerInjectables(); + if ( rulesetConfig.autoReload ) { + self.setTimeout(( ) => { + browser.tabs.update(details.tabId, { + url: details.url, + }); + }, 437); } +} - return browser.tabs.create({ - active: true, - url: pageURL.href, - }); +/******************************************************************************/ + +function setDeveloperMode(state) { + rulesetConfig.developerMode = state === true; + toggleDeveloperMode(rulesetConfig.developerMode); + broadcastMessage({ developerMode: rulesetConfig.developerMode }); + return Promise.all([ + updateUserRules(), + saveRulesetConfig(), + ]); } /******************************************************************************/ function onMessage(request, sender, callback) { + const tabId = sender?.tab?.id ?? false; + const frameId = tabId && (sender?.frameId ?? false); + // Does not require trusted origin. switch ( request.what ) { case 'insertCSS': { - const tabId = sender?.tab?.id ?? false; - const frameId = sender?.frameId ?? false; - if ( tabId === false || frameId === false ) { return; } + if ( frameId === false ) { return false; } + // https://bugs.webkit.org/show_bug.cgi?id=262491 + if ( frameId !== 0 && webextFlavor === 'safari' ) { return false; } browser.scripting.insertCSS({ css: request.css, origin: 'USER', target: { tabId, frameIds: [ frameId ] }, }).catch(reason => { - console.log(reason); + ubolErr(`insertCSS/${reason}`); }); return false; } + case 'removeCSS': { + if ( frameId === false ) { return false; } + browser.scripting.removeCSS({ + css: request.css, + origin: 'USER', + target: { tabId, frameIds: [ frameId ] }, + }).catch(reason => { + ubolErr(`removeCSS/${reason}`); + }); + return false; + } + + case 'toggleToolbarIcon': { + if ( tabId ) { + toggleToolbarIcon(tabId); + } + return false; + } + + case 'startCustomFilters': + if ( frameId === false ) { return false; } + startCustomFilters(tabId, frameId).then(( ) => { + callback(); + }); + return true; + + case 'terminateCustomFilters': + if ( frameId === false ) { return false; } + terminateCustomFilters(tabId, frameId).then(( ) => { + callback(); + }); + return true; + + case 'injectCustomFilters': + if ( frameId === false ) { return false; } + injectCustomFilters(tabId, frameId, request.hostname).then(selectors => { + callback(selectors); + }); + return true; + + case 'injectCSSProceduralAPI': + browser.scripting.executeScript({ + files: [ '/js/scripting/css-procedural-api.js' ], + target: { tabId, frameIds: [ frameId ] }, + injectImmediately: true, + }).catch(reason => { + ubolErr(`executeScript/${reason}`); + }).then(( ) => { + callback(); + }); + return true; + default: break; } @@ -176,44 +251,63 @@ // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/MessageSender // Firefox API does not set `sender.origin` - if ( sender.origin !== undefined && sender.origin !== UBOL_ORIGIN ) { return; } + if ( sender.origin !== undefined ) { + if ( sender.origin.toLowerCase() !== UBOL_ORIGIN ) { return; } + } switch ( request.what ) { case 'applyRulesets': { - enableRulesets(request.enabledRulesets).then(( ) => { - rulesetConfig.enabledRulesets = request.enabledRulesets; - return saveRulesetConfig(); - }).then(( ) => { - registerInjectables(); - callback(); - return dnr.getEnabledRulesets(); - }).then(enabledRulesets => { - broadcastMessage({ enabledRulesets }); + enableRulesets(request.enabledRulesets).then(result => { + if ( result === undefined || result.error ) { + callback(result); + return; + } + rulesetConfig.enabledRulesets = result.enabledRulesets; + return saveRulesetConfig().then(( ) => { + return registerInjectables(); + }).then(( ) => { + callback(result); + }); + }).finally(( ) => { + broadcastMessage({ enabledRulesets: rulesetConfig.enabledRulesets }); }); return true; } - case 'getOptionsPageData': { + case 'getDefaultConfig': + getDefaultRulesetsFromEnv().then(rulesets => { + callback({ + autoReload: defaultConfig.autoReload, + developerMode: defaultConfig.developerMode, + showBlockedCount: defaultConfig.showBlockedCount, + strictBlockMode: defaultConfig.strictBlockMode, + rulesets, + filteringModes: Object.assign(defaultFilteringModes), + }); + }); + return true; + + case 'getOptionsPageData': Promise.all([ + hasBroadHostPermissions(), getDefaultFilteringMode(), - getTrustedSites(), getRulesetDetails(), dnr.getEnabledRulesets(), getAdminRulesets(), adminReadEx('disabledFeatures'), ]).then(results => { const [ + hasOmnipotence, defaultFilteringMode, - trustedSites, rulesetDetails, enabledRulesets, adminRulesets, disabledFeatures, ] = results; callback({ + hasOmnipotence, defaultFilteringMode, - trustedSites: Array.from(trustedSites), enabledRulesets, adminRulesets, maxNumberOfEnabledRulesets: dnr.MAX_NUMBER_OF_ENABLED_STATIC_RULESETS, @@ -230,7 +324,24 @@ process.firstRun = false; }); return true; - } + + case 'getEnabledRulesets': + dnr.getEnabledRulesets().then(rulesets => { + callback(rulesets); + }); + return true; + + case 'getRulesetDetails': + getRulesetDetails().then(rulesetDetails => { + callback(Array.from(rulesetDetails.values())); + }); + return true; + + case 'hasBroadHostPermissions': + hasBroadHostPermissions().then(result => { + callback(result); + }); + return true; case 'setAutoReload': rulesetConfig.autoReload = request.state && true || false; @@ -261,30 +372,26 @@ return true; case 'setDeveloperMode': - rulesetConfig.developerMode = request.state; - toggleDeveloperMode(rulesetConfig.developerMode); - saveRulesetConfig().then(( ) => { + setDeveloperMode(request.state).then(( ) => { callback(); }); return true; case 'popupPanelData': { Promise.all([ + hasBroadHostPermissions(), getFilteringMode(request.hostname), - hasOmnipotence(), - hasGreatPowers(request.origin), - getEnabledRulesetsDetails(), adminReadEx('disabledFeatures'), + hasCustomFilters(request.hostname), ]).then(results => { callback({ - level: results[0], + hasOmnipotence: results[0], + level: results[1], autoReload: rulesetConfig.autoReload, - hasOmnipotence: results[1], - hasGreatPowers: results[2], - rulesetDetails: results[3], isSideloaded, developerMode: rulesetConfig.developerMode, - disabledFeatures: results[4], + disabledFeatures: results[2], + hasCustomFilters: results[3], }); }); return true; @@ -302,16 +409,20 @@ break; case 'setFilteringMode': { - getFilteringMode(request.hostname).then(actualLevel => { - if ( request.level === actualLevel ) { return actualLevel; } + getFilteringMode(request.hostname).then(beforeLevel => { + if ( request.level === beforeLevel ) { return beforeLevel; } return setFilteringMode(request.hostname, request.level); - }).then(actualLevel => { + }).then(afterLevel => { registerInjectables(); - callback(actualLevel); + callback(afterLevel); }); return true; } + case 'setPendingFilteringMode': + pendingPermissionRequest = request; + break; + case 'getDefaultFilteringMode': { getDefaultFilteringMode().then(level => { callback(level); @@ -319,34 +430,33 @@ return true; } - case 'setDefaultFilteringMode': { + case 'setDefaultFilteringMode': getDefaultFilteringMode().then(beforeLevel => setDefaultFilteringMode(request.level).then(afterLevel => ({ beforeLevel, afterLevel }) ) ).then(({ beforeLevel, afterLevel }) => { - if ( beforeLevel === 1 || afterLevel === 1 ) { - updateDynamicRules(); - } if ( afterLevel !== beforeLevel ) { registerInjectables(); } callback(afterLevel); }); return true; - } - case 'setTrustedSites': - setTrustedSites(request.hostnames).then(( ) => { + case 'getFilteringModeDetails': + getFilteringModeDetails(true).then(details => { + callback(details); + }); + return true; + + case 'setFilteringModeDetails': + setFilteringModeDetails(request.modes).then(( ) => { registerInjectables(); - return Promise.all([ - getDefaultFilteringMode(), - getTrustedSites(), - ]); - }).then(results => { - callback({ - defaultFilteringMode: results[0], - trustedSites: Array.from(results[1]), + getDefaultFilteringMode().then(defaultFilteringMode => { + broadcastMessage({ defaultFilteringMode }); + }); + getFilteringModeDetails(true).then(details => { + callback(details); }); }); return true; @@ -365,12 +475,79 @@ return true; case 'showMatchedRules': - windows.create({ + browser.windows.create({ type: 'popup', url: `/matched-rules.html?tab=${request.tabId}`, }); break; + case 'getEffectiveDynamicRules': + getEffectiveDynamicRules().then(result => { + callback(result); + }); + return true; + + case 'getEffectiveSessionRules': + getEffectiveSessionRules().then(result => { + callback(result); + }); + return true; + + case 'getEffectiveUserRules': + getEffectiveUserRules().then(result => { + callback(result); + }); + return true; + + case 'updateUserDnrRules': + updateUserRules().then(result => { + callback(result); + }); + return true; + + case 'addCustomFilters': + addCustomFilters(request.hostname, request.selectors).then(modified => { + if ( modified !== true ) { return; } + return registerInjectables(); + }).then(( ) => { + callback(); + }) + return true; + + case 'removeCustomFilters': + removeCustomFilters(request.hostname, request.selectors).then(modified => { + if ( modified !== true ) { return; } + return registerInjectables(); + }).then(( ) => { + callback(); + }); + return true; + + case 'removeAllCustomFilters': + removeAllCustomFilters(request.hostname).then(modified => { + if ( modified !== true ) { return; } + return registerInjectables(); + }).then(( ) => { + callback(); + }); + return true; + + case 'customFiltersFromHostname': + customFiltersFromHostname(request.hostname).then(selectors => { + callback(selectors); + }); + return true; + + case 'getAllCustomFilters': + getAllCustomFilters().then(data => { + callback(data); + }); + return true; + + case 'getConsoleOutput': + callback(getConsoleOutput()); + break; + default: break; } @@ -380,12 +557,42 @@ /******************************************************************************/ -async function start() { - await loadRulesetConfig(); +function onCommand(command, tab) { + switch ( command ) { + case 'enter-zapper-mode': { + if ( browser.scripting === undefined ) { return; } + browser.scripting.executeScript({ + files: [ '/js/scripting/tool-overlay.js', '/js/scripting/zapper.js' ], + target: { tabId: tab.id }, + }); + break; + } + case 'enter-picker-mode': { + if ( browser.scripting === undefined ) { return; } + browser.scripting.executeScript({ + files: [ + '/js/scripting/css-procedural-api.js', + '/js/scripting/tool-overlay.js', + '/js/scripting/picker.js', + ], + target: { tabId: tab.id }, + }); + break; + } + default: + break; + } +} +/******************************************************************************/ + +async function startSession() { const currentVersion = getCurrentVersion(); const isNewVersion = currentVersion !== rulesetConfig.version; + // Admin settings override user settings + await loadAdminConfig(); + // The default rulesets may have changed, find out new ruleset to enable, // obsolete ruleset to remove. if ( isNewVersion ) { @@ -395,83 +602,79 @@ saveRulesetConfig(); } - const rulesetsUpdated = process.wakeupRun === false && - await enableRulesets(rulesetConfig.enabledRulesets); + const rulesetsUpdated = await enableRulesets(rulesetConfig.enabledRulesets); // We need to update the regex rules only when ruleset version changes. - if ( rulesetsUpdated === false ) { + if ( rulesetsUpdated === undefined ) { if ( isNewVersion ) { updateDynamicRules(); - } else if ( process.wakeupRun === false ) { + } else { updateSessionRules(); } } // Permissions may have been removed while the extension was disabled - const permissionsChanged = await onPermissionsRemoved(); + await syncWithBrowserPermissions(); // Unsure whether the browser remembers correctly registered css/scripts // after we quit the browser. For now uBOL will check unconditionally at // launch time whether content css/scripts are properly registered. - if ( process.wakeupRun === false || permissionsChanged ) { - registerInjectables(); - - const enabledRulesets = await dnr.getEnabledRulesets(); - ubolLog(`Enabled rulesets: ${enabledRulesets}`); - - dnr.getAvailableStaticRuleCount().then(count => { - ubolLog(`Available static rule count: ${count}`); - }); - } + registerInjectables(); // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/declarativeNetRequest // Firefox API does not support `dnr.setExtensionActionOptions` - if ( process.wakeupRun === false && canShowBlockedCount ) { + if ( canShowBlockedCount ) { dnr.setExtensionActionOptions({ displayActionCountAsBadgeText: rulesetConfig.showBlockedCount, }); } - runtime.onMessage.addListener(onMessage); - - browser.permissions.onRemoved.addListener( - ( ) => { onPermissionsRemoved(); } - ); - + // Switch to basic filtering if uBOL doesn't have broad permissions at + // install time. if ( process.firstRun ) { - const enableOptimal = await hasOmnipotence(); - if ( enableOptimal ) { - const afterLevel = await setDefaultFilteringMode(MODE_OPTIMAL); - if ( afterLevel === MODE_OPTIMAL ) { - updateDynamicRules(); + const enableOptimal = await hasBroadHostPermissions(); + if ( enableOptimal === false ) { + const afterLevel = await setDefaultFilteringMode(MODE_BASIC); + if ( afterLevel === MODE_BASIC ) { registerInjectables(); process.firstRun = false; } - } else { - const disableFirstRunPage = await adminRead('disableFirstRunPage'); - if ( disableFirstRunPage !== true ) { - runtime.openOptionsPage(); - } else { - process.firstRun = false; - } } } - toggleDeveloperMode(rulesetConfig.developerMode); + // Required to ensure up to date properties are available when needed + adminReadEx('disabledFeatures').then(items => { + if ( Array.isArray(items) === false ) { return; } + if ( items.includes('develop') ) { + if ( rulesetConfig.developerMode ) { + setDeveloperMode(false); + } + } + }); +} + +/******************************************************************************/ + +async function start() { + await loadRulesetConfig(); - // Required to ensure the up to date property is available when needed if ( process.wakeupRun === false ) { - adminReadEx('disabledFeatures'); + await startSession(); } + + toggleDeveloperMode(rulesetConfig.developerMode); } +/******************************************************************************/ + // https://github.com/uBlockOrigin/uBOL-home/issues/199 // Force a restart of the extension once when an "internal error" occurs -start().then(( ) => { + +const isFullyInitialized = start().then(( ) => { localRemove('goodStart'); return false; }).catch(reason => { - console.trace(reason); + ubolErr(reason); if ( process.wakeupRun ) { return; } return localRead('goodStart').then(goodStart => { if ( goodStart === false ) { @@ -484,3 +687,29 @@ if ( restart !== true ) { return; } runtime.reload(); }); + +runtime.onMessage.addListener((request, sender, callback) => { + isFullyInitialized.then(( ) => { + const r = onMessage(request, sender, callback); + if ( r !== true ) { callback(); } + }); + return true; +}); + +browser.permissions.onRemoved.addListener((...args) => { + isFullyInitialized.then(( ) => { + onPermissionsRemoved(...args); + }); +}); + +browser.permissions.onAdded.addListener((...args) => { + isFullyInitialized.then(( ) => { + onPermissionsAdded(...args); + }); +}); + +browser.commands.onCommand.addListener((...args) => { + isFullyInitialized.then(( ) => { + onCommand(...args); + }); +}); diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/backup-restore.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/backup-restore.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/backup-restore.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/backup-restore.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,153 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2022-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { + localRead, localRemove, localWrite, + runtime, + sendMessage, +} from './ext.js'; + +/******************************************************************************/ + +export async function backupToObject(currentConfig) { + const out = {}; + const manifest = runtime.getManifest(); + out.version = manifest.versionName ?? manifest.version; + const defaultConfig = await sendMessage({ what: 'getDefaultConfig' }); + if ( currentConfig.autoReload !== defaultConfig.autoReload ) { + out.autoReload = currentConfig.autoReload; + } + if ( currentConfig.developerMode !== defaultConfig.developerMode ) { + out.developerMode = currentConfig.developerMode; + } + if ( currentConfig.showBlockedCount !== defaultConfig.showBlockedCount ) { + out.showBlockedCount = currentConfig.showBlockedCount; + } + if ( currentConfig.strictBlockMode !== defaultConfig.strictBlockMode ) { + out.strictBlockMode = currentConfig.strictBlockMode; + } + const { enabledRulesets } = currentConfig; + const customRulesets = []; + for ( const id of enabledRulesets ) { + if ( defaultConfig.rulesets.includes(id) ) { continue; } + customRulesets.push(`+${id}`); + } + for ( const id of defaultConfig.rulesets ) { + if ( enabledRulesets.includes(id) ) { continue; } + customRulesets.push(`-${id}`); + } + if ( customRulesets.length !== 0 ) { + out.rulesets = customRulesets; + } + out.filteringModes = await sendMessage({ what: 'getFilteringModeDetails' }); + const customFilters = await sendMessage({ what: 'getAllCustomFilters' }); + const filters = []; + for ( const [ hostname, selectors ] of customFilters ) { + for ( const selector of selectors ) { + filters.push(`${hostname}##${selector}`); + } + } + if ( filters.length !== 0 ) { + out.cosmeticFilters = filters; + } + const dnrRules = await localRead('userDnrRules'); + if ( typeof dnrRules === 'string' && dnrRules.length !== 0 ) { + out.dnrRules = dnrRules.split(/\n+/); + } + return out; +} + +/******************************************************************************/ + +export async function restoreFromObject(targetConfig) { + const defaultConfig = await sendMessage({ what: 'getDefaultConfig' }); + + await sendMessage({ + what: 'setAutoReload', + state: targetConfig.autoReload ?? defaultConfig.autoReload + }); + + await sendMessage({ + what: 'setShowBlockedCount', + state: targetConfig.showBlockedCount ?? defaultConfig.showBlockedCount + }); + + await sendMessage({ + what: 'setDeveloperMode', + state: targetConfig.developerMode ?? defaultConfig.developerMode + }); + + await sendMessage({ + what: 'setStrictBlockMode', + state: targetConfig.strictBlockMode ?? defaultConfig.strictBlockMode + }); + + const enabledRulesets = new Set(defaultConfig.rulesets); + for ( const entry of targetConfig.rulesets || [] ) { + const id = entry.slice(1); + if ( entry.startsWith('+') ) { + enabledRulesets.add(id); + } else if ( entry.startsWith('-') ) { + enabledRulesets.delete(id); + } + } + await sendMessage({ + what: 'applyRulesets', + enabledRulesets: Array.from(enabledRulesets), + }); + + await sendMessage({ + what: 'setFilteringModeDetails', + modes: targetConfig.filteringModes ?? defaultConfig.filteringModes, + }); + + await sendMessage({ what: 'removeAllCustomFilters', hostname: '*' }); + const hostnameMap = new Map(); + for ( const line of targetConfig.cosmeticFilters ?? [] ) { + const i = line.indexOf('##'); + if ( i === -1 ) { continue; } + const hostname = line.slice(0, i); + if ( hostname === '' ) { continue; } + const selector = line.slice(i+2); + if ( selector === '' ) { continue; } + const selectors = hostnameMap.get(hostname) || []; + if ( selectors.length === 0 ) { + hostnameMap.set(hostname, selectors) + } + selectors.push(selector); + } + const promises = []; + for ( const [ hostname, selectors ] of hostnameMap ) { + promises.push( + sendMessage({ what: 'addCustomFilters', hostname, selectors }) + ); + } + await Promise.all(promises); + + const dnrRules = targetConfig.dnrRules ?? []; + if ( dnrRules.length !== 0 ) { + await localWrite('userDnrRules', dnrRules.join('\n')); + } else { + await localRemove('userDnrRules'); + } + await sendMessage({ what: 'updateUserDnrRules' }); + +} diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/config.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/config.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/config.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/config.js 2025-10-25 19:32:51.000000000 +0000 @@ -22,6 +22,7 @@ import { localRead, localWrite, sessionRead, sessionWrite, + webextFlavor, } from './ext.js'; /******************************************************************************/ @@ -31,10 +32,13 @@ enabledRulesets: [], autoReload: true, showBlockedCount: true, - strictBlockMode: true, + strictBlockMode: webextFlavor !== 'safari', developerMode: false, + hasBroadHostPermissions: true, }; +export const defaultConfig = Object.assign({}, rulesetConfig); + export const process = { firstRun: false, wakeupRun: false, @@ -45,23 +49,13 @@ export async function loadRulesetConfig() { const sessionData = await sessionRead('rulesetConfig'); if ( sessionData ) { - rulesetConfig.version = sessionData.version; - rulesetConfig.enabledRulesets = sessionData.enabledRulesets; - rulesetConfig.autoReload = sessionData.autoReload ?? true; - rulesetConfig.showBlockedCount = sessionData.showBlockedCount ?? true; - rulesetConfig.strictBlockMode = sessionData.strictBlockMode ?? true; - rulesetConfig.developerMode = sessionData.developerMode ?? false; + Object.assign(rulesetConfig, sessionData); process.wakeupRun = true; return; } const localData = await localRead('rulesetConfig'); if ( localData ) { - rulesetConfig.version = localData.version; - rulesetConfig.enabledRulesets = localData.enabledRulesets; - rulesetConfig.autoReload = localData.autoReload ?? true; - rulesetConfig.showBlockedCount = localData.showBlockedCount ?? true; - rulesetConfig.strictBlockMode = localData.strictBlockMode ?? true; - rulesetConfig.developerMode = localData.developerMode ?? false; + Object.assign(rulesetConfig, localData) sessionWrite('rulesetConfig', rulesetConfig); return; } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/dashboard.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/dashboard.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/dashboard.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/dashboard.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,11 +19,19 @@ Home: https://github.com/gorhill/uBlock */ -import { dom } from './dom.js'; -import { runtime } from './ext.js'; +import { dom, qs$ } from './dom.js'; +import { + localRead, localRemove, localWrite, + runtime, + webextFlavor, +} from './ext.js'; +import { faIconsInit } from './fa-icons.js'; +import { i18n } from './i18n.js'; /******************************************************************************/ +dom.body.dataset.platform = webextFlavor; + { const manifest = runtime.getManifest(); dom.text('#aboutNameVer', `${manifest.name} ${manifest.version}`); @@ -32,7 +40,49 @@ dom.attr('a', 'target', '_blank'); dom.on('#dashboard-nav', 'click', '.tabButton', ev => { - dom.body.dataset.pane = ev.target.dataset.pane; + const { pane } = ev.target.dataset; + dom.body.dataset.pane = pane; + if ( pane === 'settings' ) { + localRemove('dashboard.activePane'); + } else { + localWrite('dashboard.activePane', pane); + } +}); + +localRead('dashboard.activePane').then(pane => { + if ( typeof pane !== 'string' ) { return; } + dom.body.dataset.pane = pane; }); +// Update troubleshooting on-demand +const tsinfoObserver = new IntersectionObserver(entries => { + if ( entries.every(a => a.isIntersecting === false) ) { return; } + import('./troubleshooting.js').then(module => { + return module.getTroubleshootingInfo(); + }).then(config => { + qs$('[data-i18n="supportS5H"] + pre').textContent = config; + }); +}); +tsinfoObserver.observe(qs$('[data-i18n="supportS5H"] + pre')); + +/******************************************************************************/ + +export function nodeFromTemplate(templateId, nodeSelector) { + const template = qs$(`template#${templateId}`); + const fragment = template.content.cloneNode(true); + const node = nodeSelector !== undefined + ? qs$(fragment, nodeSelector) + : fragment.firstElementChild; + faIconsInit(node); + i18n.render(node); + return node; +} + +/******************************************************************************/ + +export function hashFromIterable(iter) { + if ( Boolean(iter) === false ) { return ''; } + return Array.from(iter).sort().join('\n'); +} + /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/debug.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/debug.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/debug.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/debug.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,20 +19,85 @@ Home: https://github.com/gorhill/uBlock */ -import { dnr } from './ext.js'; +import { + dnr, + normalizeDNRRules, + webext, +} from './ext-compat.js'; + +import { + sessionRead, + sessionWrite, +} from './ext.js'; /******************************************************************************/ -export const isSideloaded = dnr.onRuleMatchedDebug instanceof Object; +const isModern = dnr.onRuleMatchedDebug instanceof Object; + +export const isSideloaded = (( ) => { + const { permissions } = webext.runtime.getManifest(); + return permissions?.includes('declarativeNetRequestFeedback') ?? false; +})(); /******************************************************************************/ +const CONSOLE_MAX_LINES = 32; +const consoleOutput = []; + +sessionRead('console').then(before => { + if ( Array.isArray(before) === false ) { return; } + for ( const s of before.reverse() ) { + consoleOutput.unshift(s); + } + consoleTruncate(); +}); + +const consoleTruncate = ( ) => { + if ( consoleOutput.length <= CONSOLE_MAX_LINES ) { return; } + consoleOutput.copyWithin(0, -CONSOLE_MAX_LINES); + consoleOutput.length = CONSOLE_MAX_LINES; +}; + +const consoleAdd = (...args) => { + if ( args.length === 0 ) { return; } + const now = new Date(); + const time = [ + `${now.getUTCMonth()+1}`.padStart(2, '0'), + `${now.getUTCDate()}`.padStart(2, '0'), + '.', + `${now.getUTCHours()}`.padStart(2, '0'), + `${now.getUTCMinutes()}`.padStart(2, '0'), + ].join(''); + for ( let i = 0; i < args.length; i++ ) { + const s = `[${time}]${args[i]}`; + if ( Boolean(s) === false ) { continue; } + if ( s === consoleOutput.at(-1) ) { continue; } + consoleOutput.push(s); + } + consoleTruncate(); + sessionWrite('console', getConsoleOutput()); +} + export const ubolLog = (...args) => { // Do not pollute dev console in stable releases. if ( isSideloaded !== true ) { return; } console.info('[uBOL]', ...args); }; +export const ubolErr = (...args) => { + if ( Array.isArray(args) === false ) { return; } + if ( globalThis.ServiceWorkerGlobalScope ) { + consoleAdd(...args); + } + // Do not pollute dev console in stable releases. + if ( isSideloaded !== true ) { return; } + console.error('[uBOL]', ...args); +}; + +export const getConsoleOutput = ( ) => { + return consoleOutput.slice(); +}; + /******************************************************************************/ const rulesets = new Map(); @@ -42,9 +107,8 @@ let writePtr = 0; const pruneLongLists = list => { - if ( list.length <= 21 ) { return list; } - return [ ...list.slice(0, 10), '...', ...list.slice(-10) ]; - + if ( list.length <= 11 ) { return list; } + return [ ...list.slice(0, 5), '...', ...list.slice(-5) ]; }; const getRuleset = async rulesetId => { @@ -57,7 +121,11 @@ } else { const response = await fetch(`/rulesets/main/${rulesetId}.json`).catch(( ) => undefined); if ( response === undefined ) { return; } - rules = await response.json().catch(( ) => undefined); + rules = await response.json().catch(( ) => + undefined + ).then(rules => + normalizeDNRRules(rules) + ); } if ( Array.isArray(rules) === false ) { return; } const ruleset = new Map(); @@ -89,21 +157,35 @@ /******************************************************************************/ export const getMatchedRules = (( ) => { - const noopFn = ( ) => Promise.resolve([]); - if ( isSideloaded !== true ) { return noopFn; } + if ( isSideloaded !== true ) { + return ( ) => Promise.resolve([]); + } + + if ( isModern ) { + return async tabId => { + const promises = []; + for ( let i = 0; i < bufferSize; i++ ) { + const j = (writePtr + i) % bufferSize; + const ruleInfo = matchedRules[j]; + if ( ruleInfo === null ) { continue; } + if ( ruleInfo.request.tabId !== -1 ) { + if ( ruleInfo.request.tabId !== tabId ) { continue; } + } + const promise = getRuleDetails(ruleInfo); + if ( promise === undefined ) { continue; } + promises.unshift(promise); + } + return Promise.all(promises); + }; + } return async tabId => { + if ( typeof dnr.getMatchedRules !== 'function' ) { return []; } + const matchedRules = await dnr.getMatchedRules({ tabId }); + if ( matchedRules instanceof Object === false ) { return []; } const promises = []; - for ( let i = 0; i < bufferSize; i++ ) { - const j = (writePtr + i) % bufferSize; - const ruleInfo = matchedRules[j]; - if ( ruleInfo === null ) { continue; } - if ( ruleInfo.request.tabId !== -1 ) { - if ( ruleInfo.request.tabId !== tabId ) { continue; } - } - const promise = getRuleDetails(ruleInfo); - if ( promise === undefined ) { continue; } - promises.unshift(promise); + for ( const { tabId, rule } of matchedRules.rulesMatchedInfo ) { + promises.push(getRuleDetails({ request: { tabId }, rule })); } return Promise.all(promises); }; @@ -118,6 +200,7 @@ export const toggleDeveloperMode = state => { if ( isSideloaded !== true ) { return; } + if ( isModern === false ) { return; } if ( state ) { dnr.onRuleMatchedDebug.addListener(matchedRuleListener); } else { diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/develop.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/develop.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/develop.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/develop.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,624 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2014-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { dom, qs$, qsa$ } from './dom.js'; +import { localRead, localWrite, sendMessage } from './ext.js'; +import { faIconsInit } from './fa-icons.js'; +import { i18n } from './i18n.js'; + +/******************************************************************************/ + +class Editor { + constructor() { + this.lastSavedText = ''; + this.view = null; + this.reYamlDocSeparator = /^(?:---|...)\s*$/; + this.modifiedRange = { start: 0, end: 0 }; + this.updateTimer = undefined; + this.ioPanel = self.cm6.createViewPanel(); + this.summaryPanel = self.cm6.createViewPanel(); + this.panels = []; + this.editors = {}; + } + + async init() { + await Promise.all([ + import('./mode-editor.js').then(module => { + this.editors['modes'] = new module.ModeEditor(this); + }), + import('./ro-dnr-editor.js').then(module => { + this.editors['dnr.ro'] = new module.ReadOnlyDNREditor(this); + }), + import('./rw-dnr-editor.js').then(module => { + this.editors['dnr.rw'] = new module.ReadWriteDNREditor(this); + }), + ]); + const rulesetDetails = await sendMessage({ what: 'getRulesetDetails' }); + const parent = qs$('#editors optgroup'); + for ( const details of rulesetDetails ) { + const option = document.createElement('option'); + option.value = `dnr.ro.${details.id}`; + option.textContent = details.name; + parent.append(option); + } + this.validModes = Array.from(qsa$('#editors option')).map(a => a.value); + const mode = await localRead('dashboard.develop.editor'); + this.editorFromMode(mode); + const text = this.normalizeEditorText(await this.editor.getText(this.mode)); + const viewConfig = { + text, + yamlLike: true, + oneDark: dom.cl.has(':root', 'dark'), + updateListener: info => { this.viewUpdateListener(info); }, + saveListener: ( ) => { this.saveEditorText(); }, + lineError: true, + spanError: true, + // https://codemirror.net/examples/autocompletion/ + autocompletion: { + override: [ + context => { + return this.autoComplete(context); + }, + ], + activateOnCompletion: ( ) => true, + }, + gutterClick: (view, info) => { + return this.gutterClick(view, info); + }, + hoverTooltip: (view, pos, side) => { + return this.hoverTooltip(view, pos, side); + }, + streamParser: this.streamParser, + foldService: (state, from) => { + return this.foldService(state, from); + }, + readOnly: this.isReadOnly(), + }; + viewConfig.panels = [ this.ioPanel, this.summaryPanel, ...this.panels ]; + this.view = self.cm6.createEditorView(viewConfig, qs$('#cm-container')); + this.lastSavedText = text; + self.cm6.foldAll(this.view); + self.cm6.resetUndoRedo(this.view); + this.updateIOPanel(); + this.editor.on?.(this); + this.modifiedRange.start = 1; + this.modifiedRange.end = this.view.state.doc.lines; + this.updateViewAsync(); + } + + normalizeEditorText(text) { + text ||= ''; + text = text.trim(); + if ( text !== '' ) { text += '\n'; } + return text; + } + + setEditorText(text, saved = false) { + text = this.normalizeEditorText(text); + if ( saved ) { + this.lastSavedText = text; + } + this.view.dispatch({ + changes: { + from: 0, to: this.view.state.doc.length, + insert: text, + }, + }); + this.view.focus(); + } + + getEditorText() { + return this.view.state.doc.toString(); + } + + editorTextChanged() { + const text = this.normalizeEditorText(this.getEditorText()); + return text !== this.lastSavedText; + } + + async selectEditor(mode) { + if ( mode === this.mode ) { return; } + this.editorFromMode(mode); + const text = await this.editor.getText(this.mode); + this.setEditorText(text); + this.lastSavedText = this.getEditorText(); + self.cm6.foldAll(this.view) + self.cm6.resetUndoRedo(this.view); + self.cm6.toggleReadOnly(this.view, this.isReadOnly()); + this.updateIOPanel(); + this.editor.on?.(this); + this.modifiedRange.start = 1; + this.modifiedRange.end = this.view.state.doc.lines; + this.updateViewAsync(); + } + + editorFromMode(mode) { + if ( this.validModes.includes(mode) === false ) { + mode = 'modes'; + } + if ( mode === this.mode ) { return mode; } + let editor; + if ( mode === 'modes' ) { + editor = this.editors['modes']; + } else if ( mode.startsWith('dnr.rw.') ) { + editor = this.editors['dnr.rw']; + } else if ( mode.startsWith('dnr.ro.') ) { + editor = this.editors['dnr.ro']; + } else { + return; + } + this.editor?.off?.(this); + this.editor = editor; + this.mode = mode; + const select = qs$('#editors'); + select.value = mode; + } + + isReadOnly() { + return typeof this.editor.saveEditorText !== 'function'; + } + + viewUpdateListener(info) { + if ( info.docChanged === false ) { return; } + for ( const transaction of info.transactions ) { + if ( transaction.docChanged === false ) { continue; } + this.addToModifiedRange(transaction); + if ( transaction.isUserEvent('delete.backward') ) { + this.smartBackspace(transaction); + } else if ( transaction.isUserEvent('input.paste') ) { + if ( this.editor.importFromPaste ) { + this.editor.importFromPaste(this, transaction); + } + } else if ( transaction.isUserEvent('input') ) { + if ( this.smartReturn(transaction) ) { continue; } + this.smartSpacebar(transaction); + } + } + this.updateViewAsync(); + } + + updateViewAsync() { + if ( this.updateTimer !== undefined ) { return; } + this.updateTimer = self.setTimeout(( ) => { + this.updateTimer = undefined; + this.updateView(); + }, 71); + } + + updateView() { + const { doc } = this.view.state; + const changed = this.editorTextChanged(); + dom.attr('#apply', 'disabled', changed ? null : ''); + dom.attr('#revert', 'disabled', changed ? null : ''); + if ( typeof this.editor.updateView !== 'function' ) { return; } + let { start, end } = this.modifiedRange; + if ( start === 0 || end === 0 ) { return; } + this.modifiedRange.start = this.modifiedRange.end = 0; + if ( start > doc.lines ) { start = doc.lines; } + if ( end > doc.lines ) { end = doc.lines; } + self.cm6.lineErrorClear(this.view, start, end); + self.cm6.spanErrorClear(this.view, start, end); + const firstLine = doc.line(start); + const lastLine = doc.line(end); + this.editor.updateView(this, firstLine, lastLine); + } + + updateIOPanel() { + const ioButtons = []; + if ( this.editor.saveEditorText ) { + ioButtons.push('apply', 'revert'); + } + if ( this.editor.importFromFile ) { + ioButtons.push('import'); + } + if ( this.editor.exportToFile ) { + ioButtons.push('export'); + } + if ( ioButtons.length === 0 ) { + return this.ioPanel.render(this.view, null); + } + const template = document.querySelector('template.io-panel'); + const fragment = template.content.cloneNode(true); + const root = fragment.querySelector('.io-panel'); + i18n.render(root); + faIconsInit(root); + root.dataset.io = ioButtons.join(' '); + const config = { + dom: root, + mount: ( ) => { + dom.on('#apply', 'click', ( ) => { + this.saveEditorText(); + }); + dom.on('#revert', 'click', ( ) => { + this.revertEditorText(); + }); + dom.on('#import', 'click', ( ) => { + this.importFromFile() + }); + dom.on('#export', 'click', ( ) => { + this.exportToFile(); + }); + } + }; + this.ioPanel.render(this.view, config); + } + + updateSummaryPanel(dom) { + if ( dom instanceof Object ) { + if ( this.updateSummaryPanel.timer !== undefined ) { + self.clearTimeout(this.updateSummaryPanel.timer); + this.updateSummaryPanel.timer = undefined; + } + return this.summaryPanel.render(this.view, { dom }); + } + if ( this.updateSummaryPanel.timer !== undefined ) { return; } + this.updateSummaryPanel.timer = self.setTimeout(( ) => { + this.updateSummaryPanel.timer = undefined; + this.summaryPanel.render(this.view, null); + }, 157); + } + + autoComplete(context) { + if ( typeof this.editor.autoComplete !== 'function' ) { return null; } + return this.editor.autoComplete(this, context); + } + + hoverTooltip(view, pos, side) { + if ( typeof this.editor.createTooltipWidget !== 'function' ) { return null; } + const details = view.domAtPos(pos); + const textNode = details.node; + if ( textNode.nodeType !== 3 ) { return null; } + const { parentElement } = textNode; + const targetElement = parentElement.closest('[data-tooltip]'); + if ( targetElement === null ) { return null; } + const tooltipText = targetElement.getAttribute('data-tooltip'); + if ( Boolean(tooltipText) === false ) { return null; } + const start = pos - details.offset; + const end = start + textNode.nodeValue.length; + if ( start === pos && side < 0 || end === pos && side > 0 ) { return null; } + return { + above: true, + pos: start, + end, + create: ( ) => { + return { dom: this.editor.createTooltipWidget(tooltipText) }; + }, + }; + } + + foldService(state, from) { + if ( typeof this.editor.foldService !== 'function' ) { return null; } + return this.editor.foldService(state, from); + } + + // Details of YAML document(s) intersecting with a text span. If the text span + // starts on a YAML document divider, the previous YAML document will be + // included. If the text span ends on a YAML document divider, the next YAML + // document will be included. + + snapToYamlDocument(doc, start, end) { + let yamlDocStart = doc.lineAt(start).number; + if ( this.reYamlDocSeparator.test(doc.line(yamlDocStart).text) ) { + if ( yamlDocStart > 1 ) { + yamlDocStart -= 1; + } + } + while ( yamlDocStart > 1 ) { + const line = doc.line(yamlDocStart); + if ( this.reYamlDocSeparator.test(line.text) ) { break; } + yamlDocStart -= 1; + } + const lastLine = doc.lines; + let yamlDocEnd = doc.lineAt(end).number; + if ( this.reYamlDocSeparator.test(doc.line(yamlDocEnd).text) ) { + if ( yamlDocEnd < lastLine ) { + yamlDocEnd += 1; + } + } + while ( yamlDocEnd < lastLine ) { + const line = doc.line(yamlDocEnd); + if ( this.reYamlDocSeparator.test(line.text) ) { break; } + yamlDocEnd += 1; + } + return { yamlDocStart, yamlDocEnd }; + } + + rangeFromTransaction(transaction) { + let from, to; + transaction.changes.iterChangedRanges((fromA, toA, fromB, toB) => { + if ( from === undefined || fromB < from ) { from = fromB; } + if ( to === undefined || toB > to ) { to = toB; } + }); + return { from, to }; + } + + addToModifiedRange(transaction) { + const { from, to } = this.rangeFromTransaction(transaction); + if ( from === undefined || to === undefined ) { return; } + const { newDoc } = transaction; + const { yamlDocStart, yamlDocEnd } = this.snapToYamlDocument(newDoc, from, to); + if ( this.modifiedRange.start === 0 || yamlDocStart < this.modifiedRange.start ) { + this.modifiedRange.start = yamlDocStart; + } + if ( this.modifiedRange.end === 0 || yamlDocEnd > this.modifiedRange.end ) { + this.modifiedRange.end = yamlDocEnd; + } + } + + lineIndentAt(line) { + const match = /^(?: {2})*/.exec(line.text); + const indent = match !== null ? match[0].length : -1; + if ( indent === -1 || (indent & 1) !== 0 ) { return -1; } + return indent / 2; + } + + getScopeAt(from, doc) { + doc ||= this.view.state.doc; + const lineFrom = doc.lineAt(from); + const out = {}; + let depth = this.lineIndentAt(lineFrom); + if ( depth === -1 ) { return out; } + const text = lineFrom.text.trim(); + if ( text.startsWith('#') ) { return out; } + const path = []; + const end = text.indexOf(':'); + if ( end !== -1 ) { + const beg = text.startsWith('- ') ? 2 : 0; + path.push(text.slice(beg, end+1)); + } + let lineNo = lineFrom.number; + while ( depth > 0 && lineNo > 1 ) { + lineNo -= 1; + const lineBefore = doc.line(lineNo); + const text = lineBefore.text.trim(); + if ( text.startsWith('#') ) { continue; } + if ( this.lineIndentAt(lineBefore) > (depth-1) ) { continue; } + const match = /^- ([^:]+:)/.exec(text); + if ( match !== null ) { + path.unshift(match[1]); + } else { + path.unshift(text); + } + depth -= 1; + } + out.scope = path.join(''); + out.depth = path.length; + return out; + } + + async saveEditorText() { + if ( typeof this.editor.saveEditorText !== 'function' ) { return; } + if ( this.editorTextChanged() === false ) { return; } + const saved = await this.editor.saveEditorText(this); + if ( saved !== true ) { return; } + this.lastSavedText = this.normalizeEditorText(this.getEditorText()); + this.updateView(); + } + + revertEditorText() { + if ( this.editorTextChanged() === false ) { return; } + this.setEditorText(this.lastSavedText); + } + + smartBackspace(transaction) { + const { from, to } = this.rangeFromTransaction(transaction); + if ( from === undefined || to === undefined ) { return; } + if ( to !== from ) { return; } + const { newDoc } = transaction; + const line = newDoc.lineAt(from); + if ( /^(?: {2})+-$/.test(line.text) === false ) { return; } + this.view.dispatch({ changes: { from: from-3, to: from, insert: '' } }); + return true; + } + + lineIsArrayItem(doc, lineNo) { + if ( lineNo < 1 || lineNo > doc.lines ) { return false; } + const line = doc.line(lineNo); + return /^(?: {2})+- /.test(line.text); + } + + smartArrayItem(doc, from) { + const line = doc.lineAt(from); + if ( line.from === 0 ) { return; } + const blanks = /^ *$/.exec(line.text); + if ( blanks === null ) { return; } + if ( this.editor.newlineAssistant ) { + const { scope } = this.getScopeAt(line.from-1, doc); + const insert = this.editor.newlineAssistant[scope]; + if ( insert ) { + this.view.dispatch({ + changes: { from: line.from, to: line.to, insert }, + selection: { anchor: line.from + insert.length }, + }); + return true; + } + } + let targetIndent; + if ( this.lineIsArrayItem(doc, line.number-1) ) { + targetIndent = doc.line(line.number-1).text.indexOf('- '); + } else if ( this.lineIsArrayItem(doc, line.number+1) ) { + targetIndent = doc.line(line.number+1).text.indexOf('- '); + } + if ( targetIndent === undefined ) { return; } + const indent = targetIndent - blanks[0].length; + if ( indent < 0 || indent > 2 ) { return; } + const insert = `${' '.repeat(indent)}- `; + this.view.dispatch({ + changes: { from, insert }, + selection: { anchor: from + insert.length }, + }); + return true; + } + + smartReturn(transaction) { + const { from, to } = this.rangeFromTransaction(transaction); + if ( from === undefined || to === undefined ) { return; } + const { newDoc } = transaction; + return this.smartArrayItem(newDoc, to); + } + + smartSpacebar(transaction) { + const { from, to } = this.rangeFromTransaction(transaction); + if ( from === undefined || to === undefined ) { return; } + if ( (to - from) !== 1 ) { return; } + const { newDoc } = transaction; + const line = newDoc.lineAt(to); + const localTo = to - line.from; + const before = line.text.slice(0, localTo); + if ( /^(?: {1}| {3})$/.test(before) === false ) { return; } + if ( this.smartArrayItem(newDoc, to) ) { return true; } + this.view.dispatch({ + changes: { from: to, insert: ' ' }, + selection: { anchor: to + 1 }, + }); + return true; + } + + gutterClick(view, info) { + const reSeparator = /^(?:---|# ---)\s*/; + const { doc } = view.state; + const lineFirst = doc.lineAt(info.from); + if ( lineFirst.text === '' ) { return false; } + let { from, to } = lineFirst; + if ( reSeparator.test(lineFirst.text) ) { + let lineNo = lineFirst.number + 1; + while ( lineNo < doc.lines ) { + const line = doc.line(lineNo); + if ( reSeparator.test(line.text) ) { break; } + to = line.to; + lineNo += 1; + } + } + view.dispatch({ + selection: { anchor: from, head: Math.min(to+1, doc.length) } + }); + view.focus(); + return true; + } + + importFromFile() { + const editor = this.editor; + if ( typeof editor.importFromFile !== 'function' ) { return; } + const input = qs$('section[data-pane="develop"] input[type="file"]'); + input.accept = editor.ioAccept || ''; + input.onchange = ev => { + input.onchange = null; + const file = ev.target.files[0]; + if ( file === undefined || file.name === '' ) { return; } + const fr = new FileReader(); + fr.onload = ( ) => { + if ( typeof fr.result !== 'string' ) { return; } + editor.importFromFile(this, fr.result); + }; + fr.readAsText(file); + }; + // Reset to empty string, this will ensure a change event is properly + // triggered if the user pick a file, even if it's the same as the last + // one picked. + input.value = ''; + input.click(); + } + + exportToFile() { + const editor = this.editor; + if ( typeof editor.exportToFile !== 'function' ) { return; } + const text = this.getEditorText(); + const result = editor.exportToFile(text); + if ( result === undefined ) { return; } + const { fname, data, mime } = result; + const a = document.createElement('a'); + a.href = `data:${mime};charset=utf-8,${encodeURIComponent(data)}`; + dom.attr(a, 'download', fname || ''); + dom.attr(a, 'type', mime); + a.click(); + } + + streamParser = { + startState: ( ) => { + return { scope: 0 }; + }, + token: (stream, state) => { + if ( stream.sol() ) { + if ( stream.match(/^---\s*$/) ) { return 'ubol-boundary'; } + if ( stream.match(/^# ---\s*$/) ) { return 'ubol-boundary ubol-comment'; } + if ( stream.match(/\.\.\.\s*$/) ) { return 'ubol-boundary'; } + } + const c = stream.peek(); + if ( c === '#' ) { + if ( (stream.pos === 0 || /\s/.test(stream.string.charAt(stream.pos - 1))) ) { + stream.skipToEnd(); + return 'ubol-comment'; + } + } + if ( stream.eatSpace() ) { return null; } + const { scope } = state; + state.scope = 0; + if ( scope === 0 && stream.match(/^[^:]+(?=:)/) ) { + state.scope = 1; + return 'ubol-keyword'; + } + if ( scope === 1 && stream.match(/^:(?: |$)/) ) { + return 'ubol-punctuation'; + } + if ( stream.match(/^- /) ) { + return 'ubol-punctuation'; + } + if ( this.editor.streamParserKeywords ) { + if ( stream.match(this.editor.streamParserKeywords) ) { + return 'ubol-literal'; + } + } + if ( stream.match(/^\S+/) ) { + return null; + } + stream.next(); + return null; + }, + languageData: { + commentTokens: { line: '#' }, + }, + tokenTable: [ + 'ubol-boundary', + 'ubol-keyword', + 'ubol-comment', + 'ubol-punctuation', + 'ubol-literal', + ], + }; +} + +/******************************************************************************/ + +async function start() { + const editor = new Editor(); + await editor.init(); + dom.on('#editors', 'change', ( ) => { + const select = qs$('#editors'); + const mode = select.value; + if ( mode === editor.mode ) { return; } + editor.selectEditor(mode); + localWrite('dashboard.develop.editor', editor.mode); + }); +} + +dom.onFirstShown(start, qs$('section[data-pane="develop"]')); + +/******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/dnr-editor.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/dnr-editor.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/dnr-editor.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/dnr-editor.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,180 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2014-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { dnr } from './ext-compat.js'; +import { rulesFromText } from './dnr-parser.js'; + +/******************************************************************************/ + +export class DNREditor { + constructor() { + this.validatedRegexes = []; + this.validatedRegexResults = []; + } + + updateView(editor, firstLine, lastLine) { + const { doc } = editor.view.state; + const text = doc.sliceString(firstLine.from, lastLine.to); + const { bad } = rulesFromText(text); + if ( Array.isArray(bad) && bad.length !== 0 ) { + self.cm6.lineErrorAdd(editor.view, bad.map(i => i + firstLine.number)); + } + const entries = self.cm6.findAll( + editor.view, + '\\bregexFilter: (\\S+)', + firstLine.from, + lastLine.to + ); + const regexes = []; + for ( const entry of entries ) { + const regex = entry.match[1]; + const i = this.validatedRegexes.indexOf(regex); + if ( i !== -1 ) { + const reason = this.validatedRegexResults[i]; + if ( reason === true ) { continue; } + self.cm6.spanErrorAdd(editor.view, entry.from+13, entry.to, reason); + } else { + regexes.push(regex); + } + } + this.validateRegexes(editor, regexes); + } + + exportToFile(text, fname) { + const { rules } = rulesFromText(text); + if ( Array.isArray(rules) === false ) { return; } + let ruleId = 1; + for ( const rule of rules ) { + rule.id = ruleId++; + } + return { + fname, + data: JSON.stringify(rules, null, 2), + mime: 'application/json', + }; + } + + async validateRegexes(editor, regexes) { + if ( regexes.length === 0 ) { return; } + const promises = regexes.map(regex => this.validateRegex(regex)); + await Promise.all(promises); + for ( const regex of regexes ) { + const i = this.validatedRegexes.indexOf(regex); + if ( i === -1 ) { continue; } + const reason = this.validatedRegexResults[i]; + if ( reason === true ) { continue; } + const entries = self.cm6.findAll(editor.view, + `(?<=\\bregexFilter: )${RegExp.escape(regex)}` + ); + for ( const entry of entries ) { + self.cm6.spanErrorAdd(editor.view, entry.from, entry.to, reason); + } + } + } + + async validateRegex(regex) { + const details = await dnr.isRegexSupported({ regex }); + const result = details.isSupported || details.reason; + if ( this.validatedRegexes.length > 32 ) { + this.validatedRegexes.pop(); + this.validatedRegexResults.pop(); + } + this.validatedRegexes.unshift(regex); + this.validatedRegexResults.unshift(result); + } + + createTooltipWidget(text) { + const template = document.querySelector('.badmark-tooltip'); + const fragment = template.content.cloneNode(true); + const dom = fragment.querySelector('.badmark-tooltip'); + dom.textContent = text; + return dom; + } + + foldService(state, from) { + const { doc } = state; + const lineFrom = doc.lineAt(from); + if ( this.reFoldable.test(lineFrom.text) === false ) { return null; } + if ( lineFrom.number <= 5 ) { return null ; } + const lineBlockStart = doc.line(lineFrom.number - 5); + if ( this.reFoldCandidates.test(lineBlockStart.text) === false ) { return null; } + for ( let i = lineFrom.number-4; i < lineFrom.number; i++ ) { + const line = doc.line(i); + if ( this.reFoldable.test(line.text) === false ) { return null; } + } + let i = lineFrom.number + 1; + for ( ; i <= doc.lines; i++ ) { + const lineNext = doc.line(i); + if ( this.reFoldable.test(lineNext.text) === false ) { break; } + } + i -= 1; + if ( i === lineFrom.number ) { return null; } + const lineFoldEnd = doc.line(i); + return { from: lineFrom.from+6, to: lineFoldEnd.to }; + } + reFoldable = /^ {4}- \S/; + reFoldCandidates = new RegExp(`^(?: {2})+${[ + 'initiatorDomains', + 'excludedInitiatorDomains', + 'requestDomains', + 'excludedRequestDomains', + ].join('|')}:$`); + + streamParserKeywords = new RegExp(`\\b(${[ + 'block', + 'redirect', + 'allow', + 'modifyHeaders', + 'upgradeScheme', + 'allowAllRequest', + 'append', + 'set', + 'remove', + 'firstParty', + 'thirdParty', + 'true', + 'false', + 'connect', + 'delete', + 'get', + 'head', + 'options', + 'patch', + 'post', + 'put', + 'other', + 'main_frame', + 'sub_frame', + 'stylesheet', + 'script', + 'image', + 'font', + 'object', + 'xmlhttprequest', + 'ping', + 'csp_report', + 'media', + 'websocket', + 'webtransport', + 'webbundle', + 'other', + ].join('|')})\\b`); +}; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/dnr-parser.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/dnr-parser.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/dnr-parser.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/dnr-parser.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,581 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2014-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +/******************************************************************************/ + +const validActionValues = [ + 'block', + 'redirect', + 'allow', + 'upgradeScheme', + 'modifyHeaders', + 'allowAllRequests', +]; + +const validBoolValues = [ + 'false', + 'true', +]; + +const validHeaderOpValues = [ + 'append', + 'remove', + 'set', +]; + +const validDomainTypeValues = [ + 'firstParty', + 'thirdParty', +]; + +const validRequestMethodValues = [ + 'connect', + 'delete', + 'get', + 'head', + 'options', + 'patch', + 'post', + 'put', + 'other', +]; + +const validResourceTypeValues = [ + 'main_frame', + 'sub_frame', + 'stylesheet', + 'script', + 'image', + 'font', + 'object', + 'xmlhttprequest', + 'ping', + 'csp_report', + 'media', + 'websocket', + 'webtransport', + 'webbundle', + 'other', +]; + +/******************************************************************************/ + +function selectParser(scope, rule, node) { + const parser = perScopeParsers[scope.join('.')]; + if ( parser === undefined ) { return false; } + return parser(scope, rule, node); +} + +const perScopeParsers = { + '': function(scope, rule, node) { + const { key, val } = node; + switch ( key ) { + case 'action': + case 'condition': + if ( val !== undefined ) { return false; } + rule[key] = {}; + scope.push(key); + break; + case 'id': { + const n = parseInt(val, 10); + if ( isNaN(n) || n < 1) { return false; } + rule.id = n; + break; + } + case 'priority': { + const n = parseInt(val, 10); + if ( isNaN(n) || n < 1 ) { return false; } + rule.priority = n; + break; + } + default: + return false; + } + return true; + }, + 'action': function(scope, rule, node) { + const { key, val } = node; + switch ( key ) { + case 'type': + if ( validActionValues.includes(val) === false ) { return false; } + rule.action.type = val; + break; + case 'redirect': + rule.action.redirect = {}; + scope.push('redirect'); + break; + case 'requestHeaders': + case 'responseHeaders': + rule.action[key] = []; + scope.push(key); + break; + default: + return false; + } + return true; + }, + 'action.redirect': function(scope, rule, node) { + const { key, val } = node; + switch ( key ) { + case 'extensionPath': + case 'regexSubstitution': + case 'url': + rule.action.redirect[key] = val; + break; + case 'transform': + rule.action.redirect.transform = {}; + scope.push('transform'); + break; + default: + return false; + } + return true; + }, + 'action.redirect.transform': function(scope, rule, node) { + const { key, val } = node; + switch ( key ) { + case 'fragment': + case 'host': + case 'path': + case 'port': + case 'query': + case 'scheme': { + if ( val === undefined ) { return false; } + rule.action.redirect.transform[key] = val; + break; + } + case 'queryTransform': + rule.action.redirect.transform.queryTransform = {}; + scope.push('queryTransform'); + break; + default: + return false; + } + return true; + }, + 'action.redirect.transform.queryTransform': function(scope, rule, node) { + const { key, val } = node; + if ( val !== undefined ) { return false; } + switch ( key ) { + case 'addOrReplaceParams': + case 'removeParams': + rule.action.redirect.transform.queryTransform[key] = []; + scope.push(key); + break; + default: + return false; + } + return true; + }, + 'action.redirect.transform.queryTransform.addOrReplaceParams': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.action.redirect.transform.queryTransform.addOrReplaceParams.push({}); + scope.push('@'); + return selectParser(scope, rule, node); + }, + 'action.redirect.transform.queryTransform.addOrReplaceParams.@': function(scope, rule, node) { + const { key, val } = node; + if ( val === undefined ) { return false; } + const item = rule.action.redirect.transform.queryTransform.addOrReplaceParams.at(-1); + switch ( key ) { + case 'key': + case 'value': + item[key] = val; + break; + case 'replaceOnly': + if ( validBoolValues.includes(val) === false ) { return false; } + item.replaceOnly = val === 'true'; + break; + default: + return false; + } + return true; + }, + 'action.redirect.transform.queryTransform.removeParams': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.action.redirect.transform.queryTransform.removeParams.push(node.val); + return true; + }, + 'action.requestHeaders': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.action.requestHeaders.push({}); + scope.push('@'); + return selectParser(scope, rule, node); + }, + 'action.requestHeaders.@': function(scope, rule, node) { + const { key, val } = node; + const item = rule.action.requestHeaders.at(-1); + switch ( key ) { + case 'header': + case 'value': + item[key] = val; + break; + case 'operation': + if ( validHeaderOpValues.includes(val) === false ) { return false; } + item.operation = val; + break; + default: + return false; + } + return true; + }, + 'action.responseHeaders': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.action.responseHeaders.push({}); + scope.push('@'); + return selectParser(scope, rule, node); + }, + 'action.responseHeaders.@': function(scope, rule, node) { + const { key, val } = node; + const item = rule.action.responseHeaders.at(-1); + switch ( key ) { + case 'header': + case 'value': + item[key] = val; + break; + case 'operation': + if ( validHeaderOpValues.includes(val) === false ) { return false; } + item.operation = val; + break; + default: + return false; + } + return true; + }, + 'condition': function(scope, rule, node) { + const { key, val } = node; + switch ( key ) { + case 'domainType': + if ( validDomainTypeValues.includes(val) === false ) { return false; } + rule.condition.domainType = val; + break; + case 'isUrlFilterCaseSensitive': + if ( validBoolValues.includes(val) === false ) { return false; } + rule.condition.isUrlFilterCaseSensitive = val === 'true'; + break; + case 'regexFilter': + case 'urlFilter': + if ( val === undefined ) { return false; } + rule.condition[key] = val; + break; + case 'initiatorDomains': + case 'excludedInitiatorDomains': + case 'requestDomains': + case 'excludedRequestDomains': + case 'resourceTypes': + case 'excludedResourceTypes': + case 'requestMethods': + case 'excludedRequestMethods': + case 'responseHeaders': + case 'excludedResponseHeaders': + rule.condition[key] = []; + scope.push(key); + break; + case 'tabIds': + rule.condition.tabIds = []; + scope.push('tabIds'); + break; + default: + return false; + } + return true; + }, + 'condition.initiatorDomains': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.condition.initiatorDomains.push(node.val); + return true; + }, + 'condition.excludedInitiatorDomains': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.condition.excludedInitiatorDomains.push(node.val); + return true; + }, + 'condition.domains': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.condition.domains.push(node.val); + return true; + }, + 'condition.excludedDomains': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.condition.excludedDomains.push(node.val); + return true; + }, + 'condition.requestDomains': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.condition.requestDomains.push(node.val); + return true; + }, + 'condition.excludedRequestDomains': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.condition.excludedRequestDomains.push(node.val); + return true; + }, + 'condition.resourceTypes': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + if ( validResourceTypeValues.includes(node.val) === false ) { return false; } + rule.condition.resourceTypes.push(node.val); + return true; + }, + 'condition.excludedResourceTypes': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + if ( validResourceTypeValues.includes(node.val) === false ) { return false; } + rule.condition.excludedResourceTypes.push(node.val); + return true; + }, + 'condition.requestMethods': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + if ( validRequestMethodValues.includes(node.val) === false ) { return false; } + rule.condition.requestMethods.push(node.val); + return true; + }, + 'condition.excludedRequestMethods': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + if ( validRequestMethodValues.includes(node.val) === false ) { return false; } + rule.condition.excludedRequestMethods.push(node.val); + return true; + }, + 'condition.responseHeaders': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.condition.responseHeaders.push({}); + scope.push('@'); + return selectParser(scope, rule, node); + }, + 'condition.responseHeaders.@': function(scope, rule, node) { + const item = rule.condition.responseHeaders.at(-1); + switch ( node.key ) { + case 'header': + if ( node.val === undefined ) { return false; } + item.header = node.val; + break; + case 'values': + case 'excludedValues': + item[node.key] = []; + scope.push(node.key); + break; + default: + return false; + } + return true; + }, + 'condition.responseHeaders.@.values': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + const item = rule.condition.responseHeaders.at(-1); + item.values.push(node.val); + return true; + }, + 'condition.responseHeaders.@.excludedValues': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + const item = rule.condition.responseHeaders.at(-1); + item.excludedValues.push(node.val); + return true; + }, + 'condition.excludedResponseHeaders': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.condition.excludedResponseHeaders.push({}); + scope.push('@'); + return selectParser(scope, rule, node); + }, + 'condition.excludedResponseHeaders.@': function(scope, rule, node) { + const item = rule.condition.excludedResponseHeaders.at(-1); + switch ( node.key ) { + case 'header': + if ( node.val === undefined ) { return false; } + item.header = node.val; + break; + case 'values': + case 'excludedValues': + item[node.key] = []; + scope.push(node.key); + break; + default: + return false; + } + return true; + }, + 'condition.excludedResponseHeaders.@.values': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + const item = rule.condition.excludedResponseHeaders.at(-1); + item.values.push(node.val); + return true; + }, + 'condition.excludedResponseHeaders.@.excludedValues': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + const item = rule.condition.excludedResponseHeaders.at(-1); + item.excludedValues.push(node.val); + return true; + }, + 'condition.tabIds': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + const n = parseInt(node.val, 10); + if ( isNaN(n) || n === 0 ) { return false; } + rule.condition.tabIds.push(n); + }, +}; + +/******************************************************************************/ + +function depthFromIndent(line) { + const match = /^\s*/.exec(line); + const count = match[0].length; + if ( (count & 1) !== 0 ) { return -1; } + return count / 2; +} + +/******************************************************************************/ + +function nodeFromLine(line) { + const match = reNodeParser.exec(line); + const out = {}; + if ( match === null ) { return out; } + if ( match[1] ) { + out.list = true; + } + if ( match[4] ) { + out.val = match[4].trim(); + } else if ( match[3] ) { + out.key = match[2]; + out.val = match[3].trim(); + if ( out.val === "''" ) { out.val = '' }; + } else { + out.key = match[2]; + } + return out; +} + +const reNodeParser = /^\s*(- )?(?:(\S+):( \S.*)?|(\S.*))$/; + +/******************************************************************************/ + +function ruleFromLines(lines, indices) { + const rule = {}; + const bad = []; + const scope = []; + for ( const i of indices ) { + const line = lines[i]; + const depth = depthFromIndent(line); + if ( depth < 0 ) { + bad.push(i); + continue; + } + scope.length = depth; + const node = nodeFromLine(line); + const result = selectParser(scope, rule, node); + if ( result === false ) { + bad.push(i); + } + } + if ( bad.length !== 0 ) { return { bad }; } + return { rule }; +} + +/******************************************************************************/ + +export function rulesFromText(text) { + const rules = []; + const bad = []; + const lines = [ ...text.split(/\n\r|\r\n|\n|\r/), '---' ]; + const indices = []; + for ( let i = 0; i < lines.length; i++ ) { + const line = lines[i].trimEnd(); + if ( line.trim().startsWith('#') ) { continue; } + if ( line !== '---' && line !== '...' ) { + indices.push(i); + continue; + } + // Discard leading empty lines + while ( indices.length !== 0 ) { + const s = lines[indices[0]].trim(); + if ( s.length !== 0 ) { break; } + indices.shift(); + } + // Discard trailing empty lines + while ( indices.length !== 0 ) { + const s = lines[indices.at(-1)].trim(); + if ( s.length !== 0 ) { break; } + indices.pop(); + } + if ( indices.length === 0 ) { continue; } + const result = ruleFromLines(lines, indices); + if ( result.bad ) { + bad.push(...result.bad.slice(4)); + } else if ( result.rule ) { + rules.push(result.rule); + } + indices.length = 0; + } + return { rules, bad }; +} + +/******************************************************************************/ + +function textFromValue(val, depth) { + const indent = ' '.repeat(depth); + switch ( typeof val ) { + case 'boolean': + case 'number': + return `${val}`; + case 'string': + if ( val === '' ) { return "''"; } + return val; + } + const out = []; + if ( Array.isArray(val) ) { + for ( const a of val ) { + const s = textFromValue(a, depth+1); + if ( s === undefined ) { continue; } + out.push(`${indent}- ${s.trimStart()}`); + } + return out.join('\n'); + } + if ( val instanceof Object ) { + for ( const [ a, b ] of Object.entries(val) ) { + const s = textFromValue(b, depth+1); + if ( s === undefined ) { continue; } + if ( b instanceof Object ) { + out.push(`${indent}${a}:\n${s}`); + } else { + out.push(`${indent}${a}: ${s}`); + } + } + return out.join('\n'); + } +} + +/******************************************************************************/ + +export function textFromRules(rules, option = {}) { + if ( Array.isArray(rules) === false ) { + if ( rules instanceof Object === false ) { return; } + rules = [ rules ]; + } + const out = []; + for ( const rule of rules ) { + if ( option.keepId !== true && rule.id ) { rule.id = undefined }; + const text = textFromValue(rule, 0); + if ( text === undefined ) { continue; } + out.push(text, '---' ); + } + if ( out.length !== 0 ) { + out.unshift('---'); + out.push(''); + } + return out.join('\n'); +} diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/ext-compat.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/ext-compat.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/ext-compat.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/ext-compat.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,103 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2022-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +export const webext = self.browser || self.chrome; +export const dnr = webext.declarativeNetRequest || {}; + +/******************************************************************************/ + +const ruleCompare = (a, b) => a.id - b.id; + +const isSameRules = (a, b) => { + a.sort(ruleCompare); + b.sort(ruleCompare); + return JSON.stringify(a) === JSON.stringify(b); +}; + +/******************************************************************************/ + +export function normalizeDNRRules(rules, ruleIds) { + if ( Array.isArray(rules) === false ) { return rules; } + return Array.isArray(ruleIds) + ? rules.filter(rule => ruleIds.includes(rule.id)) + : rules; +} + +/******************************************************************************/ + +dnr.setAllowAllRules = async function(id, allowed, notAllowed, reverse, priority) { + const [ + beforeDynamicRules, + beforeSessionRules, + ] = await Promise.all([ + dnr.getDynamicRules({ ruleIds: [ id+0 ] }), + dnr.getSessionRules({ ruleIds: [ id+1 ] }), + ]); + const addDynamicRules = []; + const addSessionRules = []; + if ( reverse || allowed.length || notAllowed.length ) { + const rule0 = { + id: id+0, + action: { type: 'allowAllRequests' }, + condition: { + resourceTypes: [ 'main_frame' ], + }, + priority, + }; + if ( allowed.length ) { + rule0.condition.requestDomains = allowed.slice(); + } else if ( notAllowed.length ) { + rule0.condition.excludedRequestDomains = notAllowed.slice(); + } + addDynamicRules.push(rule0); + // https://github.com/uBlockOrigin/uBOL-home/issues/114 + // https://github.com/uBlockOrigin/uBOL-home/issues/247 + const rule1 = { + id: id+1, + action: { type: 'allow' }, + condition: { + tabIds: [ webext.tabs.TAB_ID_NONE ], + }, + priority, + }; + if ( allowed.length ) { + rule1.condition.initiatorDomains = allowed.slice(); + } else if ( notAllowed.length ) { + rule1.condition.excludedInitiatorDomains = notAllowed.slice(); + } + addSessionRules.push(rule1); + } + if ( isSameRules(addDynamicRules, beforeDynamicRules) ) { return false; } + return Promise.all([ + dnr.updateDynamicRules({ + addRules: addDynamicRules, + removeRuleIds: beforeDynamicRules.map(r => r.id), + }), + dnr.updateSessionRules({ + addRules: addSessionRules, + removeRuleIds: beforeSessionRules.map(r => r.id), + }), + ]).then(( ) => + true + ).catch(( ) => + false + ); +}; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/ext.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/ext.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/ext.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/ext.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,17 +19,19 @@ Home: https://github.com/gorhill/uBlock */ -export const browser = - self.browser instanceof Object && - self.browser instanceof Element === false - ? self.browser - : self.chrome; +import { webext } from './ext-compat.js'; -export const dnr = browser.declarativeNetRequest; +/******************************************************************************/ + +export const browser = webext; export const i18n = browser.i18n; export const runtime = browser.runtime; -export const TAB_ID_NONE = browser.tabs.TAB_ID_NONE; -export const windows = browser.windows; + +export const webextFlavor = (( ) => { + const extURL = runtime.getURL(''); + if ( extURL.startsWith('safari-web-extension:') ) { return 'safari'; } + return extURL.startsWith('moz-extension:') ? 'firefox' : 'chromium'; +})(); /******************************************************************************/ @@ -37,21 +39,8 @@ // send a message, we try a few more times when the message fails to be sent. export function sendMessage(msg) { - return new Promise((resolve, reject) => { - let i = 5; - const send = ( ) => { - runtime.sendMessage(msg).then(response => { - resolve(response); - }).catch(reason => { - i -= 1; - if ( i <= 0 ) { - reject(reason); - } else { - setTimeout(send, 200); - } - }); - }; - send(); + return runtime.sendMessage(msg).catch(reason => { + console.log(reason); }); } @@ -64,7 +53,7 @@ const bin = await browser.storage.local.get(key); if ( bin instanceof Object === false ) { return; } return bin[key] ?? undefined; - } catch(ex) { + } catch { } } @@ -80,6 +69,17 @@ return browser.storage.local.remove(key); } +export async function localKeys() { + if ( browser.storage instanceof Object === false ) { return; } + if ( browser.storage.local instanceof Object === false ) { return; } + if ( browser.storage.local.getKeys ) { + return browser.storage.local.getKeys(); + } + const bin = await browser.storage.local.get(null); + if ( bin instanceof Object === false ) { return; } + return Object.keys(bin); +} + /******************************************************************************/ export async function sessionRead(key) { @@ -89,7 +89,7 @@ const bin = await browser.storage.session.get(key); if ( bin instanceof Object === false ) { return; } return bin[key] ?? undefined; - } catch(ex) { + } catch { } } @@ -114,7 +114,7 @@ const bin = await browser.storage.managed.get(key); if ( bin instanceof Object === false ) { return; } return bin[key] ?? undefined; - } catch(ex) { + } catch { } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/fetch.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/fetch.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/fetch.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/fetch.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,9 +19,7 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; +import { ubolErr } from './debug.js'; /******************************************************************************/ @@ -29,7 +27,7 @@ return fetch(`${path}.json`).then(response => response.json() ).catch(reason => { - console.info(reason); + ubolErr(`fetchJSON/${reason}`); }); } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/filter-lists.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/filter-lists.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/filter-lists.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/filter-lists.js 2025-10-25 19:32:51.000000000 +0000 @@ -20,6 +20,7 @@ */ import { dom, qs$, qsa$ } from './dom.js'; +import { hashFromIterable, nodeFromTemplate } from './dashboard.js'; import { i18n, i18n$ } from './i18n.js'; import { localRead, localWrite, sendMessage } from './ext.js'; @@ -28,7 +29,7 @@ export const rulesetMap = new Map(); let cachedRulesetData = {}; -let hideUnusedSet = new Set([ 'regions' ]); +let hideUnusedSet = new Set([ 'ads', 'regions' ]); /******************************************************************************/ @@ -90,14 +91,10 @@ /******************************************************************************/ function rulesetStats(rulesetId) { - const hasOmnipotence = cachedRulesetData.defaultFilteringMode > 1; const rulesetDetails = rulesetMap.get(rulesetId); if ( rulesetDetails === undefined ) { return; } const { rules, filters } = rulesetDetails; - let ruleCount = rules.plain + rules.regex; - if ( hasOmnipotence ) { - ruleCount += rules.removeparam + rules.redirect + rules.modifyHeaders; - } + const ruleCount = rules.plain + rules.regex; const filterCount = filters.accepted; return { ruleCount, filterCount }; } @@ -136,7 +133,7 @@ if ( ruleset.homeURL ) { dom.attr(qs$(listEntry, 'a.support'), 'href', ruleset.homeURL); } - dom.cl.toggle(listEntry, 'isDefault', ruleset.id === 'default'); + dom.cl.toggle(listEntry, 'isDefault', ruleset.enabled === true); const stats = rulesetStats(ruleset.id); if ( stats === undefined ) { return; } listEntry.title = listStatsTemplate @@ -144,11 +141,10 @@ .replace('{{filterCount}}', renderNumber(stats.filterCount)); const fromAdmin = isAdminRuleset(ruleset.id); dom.cl.toggle(listEntry, 'fromAdmin', fromAdmin); - const disabled = stats.ruleCount === 0 || fromAdmin; dom.attr( qs$(listEntry, '.input.checkbox input'), 'disabled', - disabled ? '' : null + fromAdmin ? '' : null ); }; @@ -166,16 +162,16 @@ const createListEntry = (listDetails, depth) => { if ( listDetails.lists === undefined ) { - return dom.clone('#templates .listEntry[data-role="leaf"]'); + return nodeFromTemplate('listEntryLeaf', '.listEntry'); } if ( depth !== 0 ) { - return dom.clone('#templates .listEntry[data-role="node"]'); + return nodeFromTemplate('listEntryNode', '.listEntry'); } - return dom.clone('#templates .listEntry[data-role="rootnode"]'); + return nodeFromTemplate('listEntryRoot', '.listEntry'); }; const createListEntries = (parentkey, listTree, depth = 0) => { - const listEntries = dom.clone('#templates .listEntries'); + const listEntries = nodeFromTemplate('listEntries', '.listEntries'); const treeEntries = Object.entries(listTree); if ( depth !== 0 ) { const reEmojis = /\p{Emoji}+/gu; @@ -216,10 +212,19 @@ [ 'default', rulesetDetails.filter(ruleset => - ruleset.id === 'default' || ruleset.group === 'default' ), ], [ + 'ads', + rulesetDetails.filter(ruleset => + ruleset.group === 'ads' + ), + ], [ + 'privacy', + rulesetDetails.filter(ruleset => + ruleset.group === 'privacy' + ), + ], [ 'malware', rulesetDetails.filter(ruleset => ruleset.group === 'malware' @@ -232,7 +237,6 @@ ], [ 'misc', rulesetDetails.filter(ruleset => - ruleset.id !== 'default' && ruleset.group === undefined && typeof ruleset.lang !== 'string' ), @@ -390,6 +394,8 @@ const applyEnabledRulesets = (( ) => { const apply = async ( ) => { + dom.cl.add(dom.body, 'committing'); + const enabledRulesets = []; for ( const liEntry of qsa$('#lists .listEntry[data-role="leaf"][data-rulesetid]') ) { const checked = qs$(liEntry, 'input[type="checkbox"]:checked') !== null; @@ -401,12 +407,17 @@ dom.cl.remove('#lists .listEntry.toggled', 'toggled'); - if ( enabledRulesets.length === 0 ) { return; } + const modified = hashFromIterable(enabledRulesets) !== + hashFromIterable(cachedRulesetData.enabledRulesets); + if ( modified ) { + const result = await sendMessage({ + what: 'applyRulesets', + enabledRulesets, + }); + dom.text('#dnrError', result?.error || ''); + } - await sendMessage({ - what: 'applyRulesets', - enabledRulesets, - }); + dom.cl.remove(dom.body, 'committing'); }; let timer; @@ -424,7 +435,11 @@ } timer = self.setTimeout(( ) => { timer = undefined; - apply(); + if ( dom.cl.has(dom.body, 'committing') ) { + applyEnabledRulesets(); + } else { + apply(); + } }, 997); } })(); diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/filter-manager-ui.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/filter-manager-ui.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/filter-manager-ui.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/filter-manager-ui.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,486 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { browser, sendMessage } from './ext.js'; +import { dom, qs$, qsa$ } from './dom.js'; +import { nodeFromTemplate } from './dashboard.js'; +import punycode from './punycode.js'; + +/******************************************************************************/ + +const dataContainer = qs$('section[data-pane="filters"] .hostnames'); + +/******************************************************************************/ + +function isValidHostname(hostname) { + try { + const url = new URL(`https://${hostname}/`); + return url.hostname === hostname; + } catch { + } + return false; +} + +/******************************************************************************/ + +function toPrettySelector(selector) { + if ( selector.startsWith('{') === false ) { return selector; } + try { + return JSON.parse(selector).raw; + } catch { + } + return selector; +} + +/******************************************************************************/ + +function hostnameFromNode(node) { + const li = node.closest('li.hostname'); + if ( li === null ) { return; } + const span = qs$(li, '.hostname[data-pretty]'); + if ( span === null ) { return; } + return span.dataset.ugly || undefined; +} + +function selectorFromNode(node) { + const li = node.closest('li.selector'); + if ( li === null ) { return; } + const span = qs$(li, '.selector[data-pretty]'); + if ( span === null ) { return; } + return span.dataset.ugly || undefined; +} + +function selectorsFromNode(node, all = false) { + const li = node.closest('li.hostname'); + if ( li === null ) { return []; } + const qsel = all + ? 'li.selector [contenteditable]' + : 'li.selector:not(.removed) [contenteditable]'; + return Array.from(qsa$(li, qsel)).map(a => a.dataset.ugly); +} + +/******************************************************************************/ + +async function removeSelectorsFromHostname(node) { + const hostnameNode = node.closest('li.hostname'); + if ( hostnameNode === null ) { return; } + const hostname = hostnameFromNode(hostnameNode); + if ( hostname === undefined ) { return; } + const selectors = Array.from( + qsa$(hostnameNode, 'li.selector.removed [contenteditable]') + ).map(a => a.dataset.ugly); + if ( selectors.length === 0 ) { return; } + dom.cl.add(dom.body, 'busy'); + updateContentEditability(); + await sendMessage({ what: 'removeCustomFilters', hostname, selectors }); + await debounceRenderCustomFilters(); + dom.cl.remove(dom.body, 'busy'); + updateContentEditability(); +} + +async function unremoveSelectorsFromHostname(node) { + const hostnameNode = node.closest('li.hostname'); + if ( hostnameNode === null ) { return; } + const hostname = hostnameFromNode(hostnameNode); + if ( hostname === undefined ) { return; } + const selectors = Array.from( + qsa$(hostnameNode, 'li.selector:not(.removed) [contenteditable]') + ).map(a => a.dataset.ugly); + if ( selectors.length === 0 ) { return; } + dom.cl.add(dom.body, 'busy'); + updateContentEditability(); + await sendMessage({ what: 'addCustomFilters', hostname, selectors }); + await debounceRenderCustomFilters(); + dom.cl.remove(dom.body, 'busy'); + updateContentEditability(); +} + +/******************************************************************************/ + +function dataFromDOM() { + const data = new Map(); + for ( const hostnameNode of qsa$('li.hostname') ) { + const hostname = hostnameFromNode(hostnameNode); + const selectors = []; + for ( const selectorNode of qsa$(hostnameNode, 'li.selector') ) { + selectors.push(selectorFromNode(selectorNode)); + } + data.set(hostname, selectors); + } + return data; +} + +/******************************************************************************/ + +async function renderCustomFilters() { + const data = await sendMessage({ what: 'getAllCustomFilters' }); + if ( Boolean(data) === false ) { return; } + const storedData = new Map(data); + const domData = dataFromDOM(); + const hostnames = Array.from( + new Set([ + ...Array.from(storedData.keys()), + ...Array.from(domData.keys()), + ]) + ).sort(); + const fragment = document.createDocumentFragment(); + for ( const hostname of hostnames ) { + const hostnameNode = nodeFromTemplate('customFiltersHostname'); + const label = qs$(hostnameNode, 'span.hostname'); + label.dataset.ugly = hostname; + const pretty = punycode.toUnicode(hostname); + label.dataset.pretty = pretty; + dom.text(label, pretty); + const storedSelectors = new Set(storedData.get(hostname)); + const domSelectors = new Set(domData.get(hostname)); + const selectors = Array.from( + new Set([ + ...Array.from(storedSelectors), + ...Array.from(domSelectors), + ]) + ).sort(); + const ulSelectors = qs$(hostnameNode, '.selectors'); + for ( const selector of selectors ) { + const selectorNode = nodeFromTemplate('customFiltersSelector'); + const label = qs$(selectorNode, 'span.selector'); + label.dataset.ugly = selector; + const pretty = toPrettySelector(selector); + label.dataset.pretty = pretty; + dom.text(label, pretty); + if ( storedSelectors.has(selector) === false ) { + dom.cl.add(selectorNode, 'removed'); + } + ulSelectors.append(selectorNode); + } + fragment.append(hostnameNode); + } + dom.remove('section[data-pane="filters"] .hostnames > .hostname'); + dataContainer.prepend(fragment); +} + +async function debounceRenderCustomFilters() { + let { debouncer } = debounceRenderCustomFilters; + if ( debouncer === undefined ) { + debouncer = debounceRenderCustomFilters.debouncer = {}; + debouncer.promise = new Promise(resolve => { + debouncer.resolve = resolve; + }); + } + if ( debouncer.timer !== undefined ) { + self.clearTimeout(debouncer.timer); + } + debouncer.timer = self.setTimeout(( ) => { + const { resolve } = debounceRenderCustomFilters.debouncer; + debounceRenderCustomFilters.debouncer = undefined; + renderCustomFilters().then(resolve); + }, 151); + return debouncer.promise; +} +debounceRenderCustomFilters.debouncer = undefined; + +/******************************************************************************/ + +function updateContentEditability() { + if ( dom.cl.has(dom.body, 'busy') ) { + dom.attr('[contenteditable]', 'contenteditable', 'false'); + return; + } + dom.attr('section[data-pane="filters"] li:not(.removed) [contenteditable]', + 'contenteditable', + 'plaintext-only' + ); + // No point editing a removed hostname + dom.attr('section[data-pane="filters"] li.hostname:not(:has(li.selector:not(.removed))) > div [contenteditable]', + 'contenteditable', + 'false' + ); + // No point editing a removed selector + dom.attr('section[data-pane="filters"] .selector.removed [contenteditable]', + 'contenteditable', + 'false' + ); +} + +/******************************************************************************/ + +async function onHostnameChanged(target, before, after) { + const uglyAfter = punycode.toASCII(after); + if ( isValidHostname(uglyAfter) === false ) { + target.textContent = before; + return; + } + + dom.cl.add(dom.body, 'busy'); + updateContentEditability(); + + // Remove old hostname from storage + await sendMessage({ what: 'removeAllCustomFilters', + hostname: target.dataset.ugly, + }); + + // Add selectors under new hostname to storage + target.dataset.ugly = uglyAfter; + target.dataset.pretty = after; + await sendMessage({ what: 'addCustomFilters', + hostname: hostnameFromNode(target), + selectors: selectorsFromNode(target), + }); + + await debounceRenderCustomFilters(); + dom.cl.remove(dom.body, 'busy'); + updateContentEditability(); +} + +async function onSelectorChanged(target, before, after) { + // Validate selector + const parserModule = await import('./static-filtering-parser.js'); + const compiler = new parserModule.ExtSelectorCompiler({ nativeCssHas: true }); + const result = {}; + if ( compiler.compile(after, result) === false ) { + target.textContent = before; + return; + } + + const hostname = hostnameFromNode(target); + + dom.cl.add(dom.body, 'busy'); + updateContentEditability(); + + // Remove old selector from storage + await sendMessage({ what: 'removeCustomFilters', + hostname, + selectors: [ target.dataset.ugly ], + }); + + // Add new selector to storage + target.dataset.ugly = result.compiled; + target.dataset.pretty = result.raw; + await sendMessage({ what: 'addCustomFilters', + hostname, + selectors: [ result.compiled ], + }); + + await debounceRenderCustomFilters(); + dom.cl.remove(dom.body, 'busy'); + updateContentEditability(); +} + +function onTextChanged(target) { + const before = target.dataset.pretty; + const after = target.textContent.trim(); + if ( after !== target.textContent ) { + target.textContent = after; + } + if ( after === before ) { return; } + if ( after === '' ) { + target.textContent = before; + return; + } + if ( target.matches('.hostname') ) { + onHostnameChanged(target, before, after); + } else if ( target.matches('.selector') ) { + onSelectorChanged(target, before, after); + } +} + +/******************************************************************************/ + +function startEdit(ev) { + focusedEditableContent = ev.target; +} + +function endEdit(ev) { + const { target } = ev; + if ( target.textContent !== target.dataset.pretty ) { + onTextChanged(target); + } + focusedEditableContent = null; +} + +function commitEdit(ev) { + const { target } = ev; + if ( target === focusedEditableContent ) { + if ( ev.inputType === 'insertLineBreak' ) { target.blur(); } + return; + } + onTextChanged(target); +} + +let focusedEditableContent = null; + +/******************************************************************************/ + +function onTrashClicked(ev) { + const { target } = ev; + const node = target.closest('li.selector'); + if ( node ) { + dom.cl.add(node, 'removed'); + } else { + dom.cl.add(qsa$(target.closest('li.hostname'), 'li.selector'), 'removed'); + } + removeSelectorsFromHostname(target); +} + +function onUndoClicked(ev) { + const { target } = ev; + const node = target.closest('li.selector'); + if ( node ) { + dom.cl.remove(node, 'removed'); + } else { + dom.cl.remove(qsa$(target.closest('li.hostname'), 'li.selector'), 'removed'); + } + unremoveSelectorsFromHostname(target); +} + +/******************************************************************************/ + +async function importFromText(text) { + const parserModule = await import('./static-filtering-parser.js'); + const parser = new parserModule.AstFilterParser({ nativeCssHas: true }); + const lines = text.split(/\n/); + const hostnameToSelectorsMap = new Map(); + + for ( const line of lines ) { + parser.parse(line); + if ( parser.hasError() ) { continue; } + if ( parser.isCosmeticFilter() === false ) { continue; } + if ( parser.hasOptions() === false ) { continue; } + const { compiled, exception } = parser.result; + if ( compiled === undefined ) { continue; } + if ( exception ) { continue; } + const hostnames = new Set(); + for ( const { hn, not, bad } of parser.getExtFilterDomainIterator() ) { + if ( bad ) { continue; } + if ( hn.includes('/') ) { continue; } + if ( hn.includes('*') ) { continue; } + if ( not ) { hostnames.length = 0; break; } + hostnames.add(hn); + } + for ( const hn of hostnames ) { + const selectors = hostnameToSelectorsMap.get(hn) || new Set(); + if ( selectors.size === 0 ) { + hostnameToSelectorsMap.set(hn, selectors) + } + selectors.add(compiled); + } + } + + if ( hostnameToSelectorsMap.size === 0 ) { return; } + + dom.cl.add(dom.body, 'busy'); + updateContentEditability(); + + const promises = []; + for ( const [ hostname, selectors ] of hostnameToSelectorsMap ) { + promises.push( + sendMessage({ what: 'addCustomFilters', + hostname, + selectors: Array.from(selectors), + }) + ); + } + await Promise.all(promises); + + await debounceRenderCustomFilters(); + dom.cl.remove(dom.body, 'busy'); + updateContentEditability(); +} + +/******************************************************************************/ + +function importFromTextarea() { + dom.prop('section[data-pane="filters"] details', 'open', false); + const textarea = qs$('section[data-pane="filters"] .importFromText textarea'); + importFromText(textarea.value); + textarea.value = ''; +} + +/******************************************************************************/ + +function importFromFile() { + const input = qs$('section[data-pane="filters"] input[type="file"]'); + input.onchange = ev => { + input.onchange = null; + const file = ev.target.files[0]; + if ( file === undefined || file.name === '' ) { return; } + const fr = new FileReader(); + fr.onload = ( ) => { + if ( typeof fr.result !== 'string' ) { return; } + importFromText(fr.result); + }; + fr.readAsText(file); + }; + // Reset to empty string, this will ensure a change event is properly + // triggered if the user pick a file, even if it's the same as the last + // one picked. + input.value = ''; + input.click(); + dom.prop('section[data-pane="filters"] details', 'open', false); +} + +/******************************************************************************/ + +function exportToFile() { + const lines = []; + for ( const hostnameNode of qsa$('.hostnames li.hostname') ) { + const hostname = punycode.toUnicode(hostnameFromNode(hostnameNode)); + const selectors = selectorsFromNode(hostnameNode); + for ( const selector of selectors ) { + lines.push(`${hostname}##${toPrettySelector(selector)}`); + } + lines.push(''); + } + const text = lines.join('\n').trim(); + if ( text.length === 0 ) { return; } + const a = document.createElement('a'); + a.href = `data:text/plain;charset=utf-8,${encodeURIComponent(text + '\n')}`; + dom.attr(a, 'download', 'my-ubol-filters.txt'); + dom.attr(a, 'type', 'text/plain'); + a.click(); + dom.prop('section[data-pane="filters"] details', 'open', false); +} + +/******************************************************************************/ + +async function start() { + renderCustomFilters(); + + dom.on(dataContainer, 'focusin', 'section[data-pane="filters"] [contenteditable]', startEdit); + dom.on(dataContainer, 'focusout', 'section[data-pane="filters"] [contenteditable]', endEdit); + dom.on(dataContainer, 'input', 'section[data-pane="filters"] [contenteditable]', commitEdit); + dom.on(dataContainer, 'click', 'section[data-pane="filters"] .remove', onTrashClicked); + dom.on(dataContainer, 'click', 'section[data-pane="filters"] .undo', onUndoClicked); + dom.on('section[data-pane="filters"] [data-i18n="addButton"]', 'click', importFromTextarea); + dom.on('section[data-pane="filters"] [data-i18n="importAndAppendButton"]', 'click', importFromFile); + dom.on('section[data-pane="filters"] [data-i18n="exportButton"]', 'click', exportToFile); + + browser.storage.local.onChanged.addListener((changes, area) => { + if ( area !== undefined && area !== 'local' ) { return; } + if ( Object.keys(changes).some(a => a.startsWith('site.')) ) { + debounceRenderCustomFilters(); + } + }); +} + +/******************************************************************************/ + +// Update pane on-demand +dom.onFirstShown(start, qs$('section[data-pane="filters"]')); diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/filter-manager.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/filter-manager.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/filter-manager.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/filter-manager.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,277 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2022-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { + browser, + localKeys, + localRead, + localRemove, + localWrite, +} from './ext.js'; + +import { + intersectHostnameIters, + matchesFromHostnames, + strArrayEq, + subtractHostnameIters, +} from './utils.js'; + +import { ubolErr } from './debug.js'; + +/******************************************************************************/ + +async function flushWrites() { + while ( pendingWrites.length !== 0 ) { + const promises = pendingWrites; + pendingWrites.length = 0; + await Promise.all(promises); + } +} + +async function keysFromStorage() { + await flushWrites(); + return localKeys(); +} + +async function readFromStorage(key) { + await flushWrites(); + return localRead(key); +} + +async function writeToStorage(key, value) { + pendingWrites.push(localWrite(key, value)); +} + +async function removeFromStorage(key) { + pendingWrites.push(localRemove(key)); +} + +const pendingWrites = []; + +/******************************************************************************/ + +export async function customFiltersFromHostname(hostname) { + const promises = []; + let hn = hostname; + while ( hn !== '' ) { + promises.push(readFromStorage(`site.${hn}`)); + const pos = hn.indexOf('.'); + if ( pos === -1 ) { break; } + hn = hn.slice(pos + 1); + } + const results = await Promise.all(promises); + const out = []; + for ( let i = 0; i < promises.length; i++ ) { + const selectors = results[i]; + if ( selectors === undefined ) { continue; } + selectors.forEach(selector => { + out.push(selector.startsWith('0') ? selector.slice(1) : selector); + }); + } + return out.sort(); +} + +/******************************************************************************/ + +export async function hasCustomFilters(hostname) { + const selectors = await customFiltersFromHostname(hostname); + return selectors?.length ?? 0; +} + +/******************************************************************************/ + +async function getAllCustomFilterKeys() { + const storageKeys = await keysFromStorage() || []; + return storageKeys.filter(a => a.startsWith('site.')); +} + +/******************************************************************************/ + +export async function getAllCustomFilters() { + const collect = async key => { + const selectors = await readFromStorage(key); + return [ key.slice(5), selectors.map(a => a.startsWith('0') ? a.slice(1) : a) ]; + }; + const keys = await getAllCustomFilterKeys(); + const promises = keys.map(k => collect(k)); + return Promise.all(promises); +} + +/******************************************************************************/ + +export function startCustomFilters(tabId, frameId) { + return browser.scripting.executeScript({ + files: [ '/js/scripting/css-user.js' ], + target: { tabId, frameIds: [ frameId ] }, + injectImmediately: true, + }).catch(reason => { + ubolErr(`startCustomFilters/${reason}`); + }) +} + +export function terminateCustomFilters(tabId, frameId) { + return browser.scripting.executeScript({ + files: [ '/js/scripting/css-user-terminate.js' ], + target: { tabId, frameIds: [ frameId ] }, + injectImmediately: true, + }).catch(reason => { + ubolErr(`terminateCustomFilters/${reason}`); + }) +} + +/******************************************************************************/ + +export async function injectCustomFilters(tabId, frameId, hostname) { + const selectors = await customFiltersFromHostname(hostname); + if ( selectors.length === 0 ) { return; } + const promises = []; + const plainSelectors = selectors.filter(a => a.startsWith('{') === false); + if ( plainSelectors.length !== 0 ) { + promises.push( + browser.scripting.insertCSS({ + css: `${plainSelectors.join(',\n')}{display:none!important;}`, + origin: 'USER', + target: { tabId, frameIds: [ frameId ] }, + }).catch(reason => { + ubolErr(`injectCustomFilters/insertCSS/${reason}`); + }) + ); + } + const proceduralSelectors = selectors.filter(a => a.startsWith('{')); + if ( proceduralSelectors.length !== 0 ) { + promises.push( + browser.scripting.executeScript({ + files: [ '/js/scripting/css-procedural-api.js' ], + target: { tabId, frameIds: [ frameId ] }, + injectImmediately: true, + }).catch(reason => { + ubolErr(`injectCustomFilters/executeScript/${reason}`); + }) + ); + } + await Promise.all(promises); + return { plainSelectors, proceduralSelectors }; +} + +/******************************************************************************/ + +export async function registerCustomFilters(context) { + const siteKeys = await getAllCustomFilterKeys(); + if ( siteKeys.length === 0 ) { return; } + + const { none } = context.filteringModeDetails; + let hostnames = siteKeys.map(a => a.slice(5)); + if ( none.has('all-urls') ) { + const { basic, optimal, complete } = context.filteringModeDetails; + hostnames = intersectHostnameIters(hostnames, [ + ...basic, ...optimal, ...complete + ]); + } else if ( none.size !== 0 ) { + hostnames = [ ...subtractHostnameIters(hostnames, none) ]; + } + if ( hostnames.length === 0 ) { return; } + + const registered = context.before.get('css-user'); + context.before.delete('css-user'); // Important! + + const directive = { + id: 'css-user', + js: [ '/js/scripting/css-user.js' ], + matches: matchesFromHostnames(hostnames), + runAt: 'document_start', + }; + + if ( registered === undefined ) { + context.toAdd.push(directive); + } else if ( strArrayEq(registered.matches, directive.matches) === false ) { + context.toRemove.push('css-user'); + context.toAdd.push(directive); + } +} + +/******************************************************************************/ + +export async function addCustomFilters(hostname, toAdd) { + if ( hostname === '' ) { return false; } + const key = `site.${hostname}`; + const selectors = await readFromStorage(key) || []; + const countBefore = selectors.length; + for ( const selector of toAdd ) { + if ( selectors.includes(selector) ) { continue; } + selectors.push(selector); + } + if ( selectors.length === countBefore ) { return false; } + selectors.sort(); + writeToStorage(key, selectors); + return true; +} + +/******************************************************************************/ + +export async function removeAllCustomFilters(hostname) { + if ( hostname === '*' ) { + const keys = await getAllCustomFilterKeys(); + if ( keys.length === 0 ) { return false; } + for ( const key of keys ) { + removeFromStorage(key); + } + return true; + } + const key = `site.${hostname}`; + const selectors = await readFromStorage(key) || []; + removeFromStorage(key); + return selectors.length !== 0; +} + +export async function removeCustomFilters(hostname, selectors) { + const promises = []; + let hn = hostname; + while ( hn !== '' ) { + promises.push(removeCustomFiltersByKey(`site.${hn}`, selectors)); + const pos = hn.indexOf('.'); + if ( pos === -1 ) { break; } + hn = hn.slice(pos + 1); + } + const results = await Promise.all(promises); + return results.some(a => a); +} + +async function removeCustomFiltersByKey(key, toRemove) { + const selectors = await readFromStorage(key); + if ( selectors === undefined ) { return false; } + const beforeCount = selectors.length; + for ( const selector of toRemove ) { + let i = selectors.indexOf(selector); + if ( i === -1 ) { + i = selectors.indexOf(`0${selector}`); + if ( i === -1 ) { continue; } + } + selectors.splice(i, 1); + } + const afterCount = selectors.length; + if ( afterCount === beforeCount ) { return false; } + if ( afterCount !== 0 ) { + writeToStorage(key, selectors); + } else { + removeFromStorage(key); + } + return true; +} diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/mode-editor.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/mode-editor.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/mode-editor.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/mode-editor.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,91 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2014-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { + modesFromText, + textFromModes, +} from './mode-parser.js'; +import { i18n$ } from './i18n.js'; +import { sendMessage } from './ext.js'; + +/******************************************************************************/ + +export class ModeEditor { + constructor(editor) { + this.editor = editor; + this.bc = null; + } + + on() { + if ( this.bc !== null ) { return; } + this.bc = new self.BroadcastChannel('uBOL'); + this.bc.onmessage = ev => { + const message = ev.data; + if ( message instanceof Object === false ) { return; } + if ( message.filteringModeDetails === undefined ) { return; } + // TODO: merge with ongoing edits? + const text = textFromModes(message.filteringModeDetails); + this.editor.setEditorText(text, true); + }; + } + + off() { + if ( this.bc === null ) { return; } + this.bc.onmessage = null; + this.bc = null; + } + + async getText() { + const modes = await sendMessage({ what: 'getFilteringModeDetails' }); + return textFromModes(modes); + } + + async saveEditorText(editor) { + const { modes } = modesFromText(editor.getEditorText()); + if ( modes instanceof Object === false ) { return; } + const modesAfter = await sendMessage({ what: 'setFilteringModeDetails', modes }); + const text = textFromModes(modesAfter); + editor.setEditorText(text); + return true; + } + + updateView(editor, firstLine, lastLine) { + const { doc } = editor.view.state; + const text = doc.sliceString(firstLine.from, lastLine.to); + const { bad } = modesFromText(text, true); + if ( Array.isArray(bad) && bad.length !== 0 ) { + self.cm6.lineErrorAdd(editor.view, bad.map(i => i + firstLine.number)); + } + } + + newlineAssistant = { + 'no filtering:': ' - ', + 'basic:': ' - ', + 'optimal:': ' - ', + 'complete:': ' - ', + [`${i18n$('filteringMode0Name')}:`]: ' - ', + [`${i18n$('filteringMode1Name')}:`]: ' - ', + [`${i18n$('filteringMode2Name')}:`]: ' - ', + [`${i18n$('filteringMode3Name')}:`]: ' - ', + }; + + ioAccept = '.json,application/json'; +}; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/mode-manager.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/mode-manager.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/mode-manager.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/mode-manager.js 2025-10-25 19:32:51.000000000 +0000 @@ -21,6 +21,7 @@ import { broadcastMessage, + hasBroadHostPermissions, hostnamesFromMatches, isDescendantHostnameOfIter, toBroaderHostname, @@ -32,6 +33,11 @@ sessionRead, sessionWrite, } from './ext.js'; +import { + rulesetConfig, + saveRulesetConfig, +} from './config.js'; + import { adminReadEx } from './admin.js'; import { filteringModesToDNR } from './ruleset-manager.js'; @@ -47,6 +53,13 @@ export const MODE_OPTIMAL = 2; export const MODE_COMPLETE = 3; +export const defaultFilteringModes = { + none: [], + basic: [], + optimal: [ 'all-urls' ], + complete: [], +}; + /******************************************************************************/ const pruneDescendantHostnamesFromSet = (hostname, hnSet) => { @@ -218,15 +231,29 @@ return readFilteringModeDetails.cache; } } - let [ userModes, adminNoFiltering ] = await Promise.all([ + let [ + userModes = structuredClone(defaultFilteringModes), + adminDefaultFiltering, + adminNoFiltering, + ] = await Promise.all([ localRead('filteringModeDetails'), + adminReadEx('defaultFiltering'), adminReadEx('noFiltering'), ]); - if ( userModes === undefined ) { - userModes = { basic: [ 'all-urls' ] }; - } userModes = unserializeModeDetails(userModes); - if ( Array.isArray(adminNoFiltering) ) { + if ( adminDefaultFiltering !== undefined ) { + const modefromName = { + none: MODE_NONE, + basic: MODE_BASIC, + optimal: MODE_OPTIMAL, + complete: MODE_COMPLETE, + }; + const adminDefaultFilteringMode = modefromName[adminDefaultFiltering]; + if ( adminDefaultFilteringMode !== undefined ) { + applyFilteringMode(userModes, 'all-urls', adminDefaultFilteringMode); + } + } + if ( Array.isArray(adminNoFiltering) && adminNoFiltering.length !== 0 ) { if ( adminNoFiltering.includes('-*') ) { userModes.none.clear(); } @@ -254,27 +281,34 @@ readFilteringModeDetails.cache = unserializeModeDetails(data); return Promise.all([ getDefaultFilteringMode(), - getTrustedSites(), + hasBroadHostPermissions(), localWrite('filteringModeDetails', data), sessionWrite('filteringModeDetails', data), ]).then(results => { broadcastMessage({ defaultFilteringMode: results[0], - trustedSites: Array.from(results[1]), + hasOmnipotence: results[1], + filteringModeDetails: readFilteringModeDetails.cache, }); }); } /******************************************************************************/ -export async function getFilteringModeDetails() { +export async function getFilteringModeDetails(serializable = false) { const actualDetails = await readFilteringModeDetails(); - return { + const out = { none: new Set(actualDetails.none), basic: new Set(actualDetails.basic), optimal: new Set(actualDetails.optimal), complete: new Set(actualDetails.complete), }; + return serializable ? serializeModeDetails(out) : out; +} + +export async function setFilteringModeDetails(details) { + await localWrite('filteringModeDetails', serializeModeDetails(details)); + await readFilteringModeDetails(true); } /******************************************************************************/ @@ -303,66 +337,51 @@ /******************************************************************************/ -export async function getTrustedSites() { - const filteringModes = await getFilteringModeDetails(); - return filteringModes.none; -} - -export async function setTrustedSites(hostnames) { - const filteringModes = await getFilteringModeDetails(); - const { none } = filteringModes; - const hnSet = new Set(hostnames); - let modified = false; - // Set default mode to Basic when removing No-filtering as default mode - if ( none.has('all-urls') && hnSet.has('all-urls') === false ) { - applyFilteringMode(filteringModes, 'all-urls', MODE_BASIC); - modified = true; - } - for ( const hn of none ) { - if ( hnSet.has(hn) ) { - hnSet.delete(hn); - } else { - none.delete(hn); - modified = true; - } - } - for ( const hn of hnSet ) { - const level = applyFilteringMode(filteringModes, hn, MODE_NONE); - if ( level !== MODE_NONE ) { continue; } - modified = true; - } - if ( modified === false ) { return; } - return writeFilteringModeDetails(filteringModes); -} - -/******************************************************************************/ - export async function syncWithBrowserPermissions() { - const [ permissions, beforeMode ] = await Promise.all([ + const [ + permissions, + beforeMode, + ] = await Promise.all([ browser.permissions.getAll(), getDefaultFilteringMode(), ]); const allowedHostnames = new Set(hostnamesFromMatches(permissions.origins || [])); + const hasBroadHostPermissions = allowedHostnames.has('all-urls'); + const broadHostPermissionsToggled = + hasBroadHostPermissions !== rulesetConfig.hasBroadHostPermissions; let modified = false; - if ( beforeMode > MODE_BASIC && allowedHostnames.has('all-urls') === false ) { + if ( beforeMode > MODE_BASIC && hasBroadHostPermissions === false ) { await setDefaultFilteringMode(MODE_BASIC); modified = true; + } else if ( beforeMode === MODE_BASIC && hasBroadHostPermissions && broadHostPermissionsToggled ) { + await setDefaultFilteringMode(MODE_OPTIMAL); + modified = true; + } + if ( broadHostPermissionsToggled ) { + rulesetConfig.hasBroadHostPermissions = hasBroadHostPermissions; + saveRulesetConfig(); } const afterMode = await getDefaultFilteringMode(); - if ( afterMode > MODE_BASIC ) { return false; } + if ( afterMode > MODE_BASIC ) { return afterMode !== beforeMode; } const filteringModes = await getFilteringModeDetails(); - const { optimal, complete } = filteringModes; - for ( const hn of optimal ) { - if ( allowedHostnames.has(hn) ) { continue; } - optimal.delete(hn); - modified = true; - } - for ( const hn of complete ) { - if ( allowedHostnames.has(hn) ) { continue; } - complete.delete(hn); - modified = true; + if ( allowedHostnames.has('all-urls') === false ) { + const { optimal, complete } = filteringModes; + for ( const hn of optimal ) { + if ( allowedHostnames.has(hn) ) { continue; } + if ( isDescendantHostnameOfIter(hn, allowedHostnames) ) { continue; } + optimal.delete(hn); + modified = true; + } + for ( const hn of complete ) { + if ( allowedHostnames.has(hn) ) { continue; } + if ( isDescendantHostnameOfIter(hn, allowedHostnames) ) { continue; } + complete.delete(hn); + modified = true; + } + if ( modified ) { + await writeFilteringModeDetails(filteringModes); + } } - await writeFilteringModeDetails(filteringModes); return modified; } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/mode-parser.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/mode-parser.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/mode-parser.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/mode-parser.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,211 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2014-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { i18n$ } from './i18n.js'; +import punycode from './punycode.js'; + +/******************************************************************************/ + +function selectParser(scope, modes, node) { + const parser = perScopeParsers[scope.join('.')]; + if ( parser === undefined ) { return false; } + return parser(scope, modes, node); +} + +const validModes = [ + 'none', + 'basic', + 'optimal', + 'complete', +]; + +const uglyModeNames = { + [i18n$('filteringMode0Name')]: 'none', + [i18n$('filteringMode1Name')]: 'basic', + [i18n$('filteringMode2Name')]: 'optimal', + [i18n$('filteringMode3Name')]: 'complete', +}; + +const prettyModeNames = { + none: i18n$('filteringMode0Name'), + basic: i18n$('filteringMode1Name'), + optimal: i18n$('filteringMode2Name'), + complete: i18n$('filteringMode3Name'), +}; + +const perScopeParsers = { + '': function(scope, modes, node) { + const { key, val } = node; + switch ( key ) { + case 'none': + case 'basic': + case 'optimal': + case 'complete': + case prettyModeNames.none: + case prettyModeNames.basic: + case prettyModeNames.optimal: + case prettyModeNames.complete: { + const mode = uglyModeNames[key] || key; + if ( val !== undefined ) { return false; } + modes[mode] ||= []; + scope.push(mode); + break; + } + default: + return false; + } + return true; + }, + none: function(scope, modes, node) { + return addHostnameToMode(modes, 'none', node) + }, + basic: function(scope, modes, node) { + return addHostnameToMode(modes, 'basic', node) + }, + optimal: function(scope, modes, node) { + return addHostnameToMode(modes, 'optimal', node) + }, + complete: function(scope, modes, node) { + return addHostnameToMode(modes, 'complete', node) + }, +}; + +const addHostnameToMode = (modes, mode, node) => { + if ( node.list !== true ) { return false; } + modes[mode].push(punycode.toASCII(node.val)); +}; + +/******************************************************************************/ + +function depthFromIndent(line) { + const match = /^\s*/.exec(line); + const count = match[0].length; + if ( (count & 1) !== 0 ) { return -1; } + return count / 2; +} + +/******************************************************************************/ + +function nodeFromLine(line) { + const match = reNodeParser.exec(line); + const out = {}; + if ( match === null ) { return out; } + if ( match[1] ) { + out.list = true; + } + if ( match[4] ) { + out.val = match[4].trim(); + } else if ( match[3] ) { + out.key = match[2]; + out.val = match[3].trim(); + if ( out.val === "''" ) { out.val = '' }; + } else { + out.key = match[2]; + } + return out; +} + +const reNodeParser = /^\s*(- )?(?:([^:]+):( \S.*)?|(\S.*))$/; + +/******************************************************************************/ + +export function modesFromText(text, justbad = false) { + const lines = [ ...text.split(/\n\r|\r\n|\n|\r/) ]; + const indices = []; + for ( let i = 0; i < lines.length; i++ ) { + const line = lines[i].trimEnd(); + if ( line.trim().startsWith('#') ) { continue; } + indices.push(i); + } + // Discard leading empty lines + while ( indices.length !== 0 ) { + const s = lines[indices[0]].trim(); + if ( s.length !== 0 ) { break; } + indices.shift(); + } + // Discard trailing empty lines + while ( indices.length !== 0 ) { + const s = lines[indices.at(-1)].trim(); + if ( s.length !== 0 ) { break; } + indices.pop(); + } + // Parse + const modes = {}; + const bad = []; + const scope = []; + for ( const i of indices ) { + const line = lines[i]; + const depth = depthFromIndent(line); + if ( depth < 0 ) { + bad.push(i); + continue; + } + scope.length = depth; + const node = nodeFromLine(line); + const result = selectParser(scope, modes, node); + if ( result === false ) { + bad.push(i); + } + } + if ( justbad ) { + return bad.length !== 0 ? { bad } : { }; + } + // Ensure all modes are present, and that one mode is the default one + const seen = new Map(); + let defaultMode = ''; + for ( const mode of validModes ) { + modes[mode] = new Set(modes[mode]); + if ( modes[mode].has('all-urls') ) { + defaultMode = mode; + } + for ( const hn of modes[mode] ) { + if ( seen.has(hn) ) { + modes[seen.get(hn)].delete(hn); + } + seen.set(hn, mode); + } + } + if ( defaultMode === '' ) { + defaultMode = 'optimal'; + } + modes[defaultMode].clear(); + modes[defaultMode].add('all-urls'); + for ( const mode of validModes ) { + modes[mode] = Array.from(modes[mode]); + } + return { modes }; +} + +/******************************************************************************/ + +export function textFromModes(modes) { + const out = []; + for ( const mode of validModes ) { + const hostnames = modes[mode]; + if ( hostnames === undefined ) { continue; } + out.push(`${prettyModeNames[mode]}:`); + for ( const hn of hostnames ) { + out.push(` - ${punycode.toUnicode(hn)}`); + } + } + out.push(''); + return out.join('\n'); +} diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/picker-ui.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/picker-ui.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/picker-ui.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/picker-ui.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,422 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { dom, qs$, qsa$ } from './dom.js'; +import { localRead, localWrite } from './ext.js'; +import { ExtSelectorCompiler } from './static-filtering-parser.js'; +import { toolOverlay } from './tool-overlay-ui.js'; + +/******************************************************************************/ + +const selectorCompiler = new ExtSelectorCompiler({ nativeCssHas: true }); + +let selectorPartsDB = new Map(); +let sliderParts = []; +let sliderPartsPos = -1; + +/******************************************************************************/ + +function validateSelector(selector) { + validateSelector.error = undefined; + if ( selector === '' ) { return; } + const result = {}; + if ( selectorCompiler.compile(selector, result) ) { + return result.compiled; + } + validateSelector.error = 'Error'; +} + +/******************************************************************************/ + +function onSvgTouch(ev) { + if ( ev.type === 'touchstart' ) { + onSvgTouch.x0 = ev.touches[0].screenX; + onSvgTouch.y0 = ev.touches[0].screenY; + onSvgTouch.t0 = ev.timeStamp; + return; + } + if ( onSvgTouch.x0 === undefined ) { return; } + const stopX = ev.changedTouches[0].screenX; + const stopY = ev.changedTouches[0].screenY; + const distance = Math.sqrt( + Math.pow(stopX - onSvgTouch.x0, 2) + + Math.pow(stopY - onSvgTouch.y0, 2) + ); + // Interpret touch events as a tap if: + // - Swipe is not valid; and + // - The time between start and stop was less than 200ms. + const duration = ev.timeStamp - onSvgTouch.t0; + if ( distance >= 32 || duration >= 200 ) { return; } + onSvgClicked({ + type: 'touch', + target: ev.target, + clientX: ev.changedTouches[0].pageX, + clientY: ev.changedTouches[0].pageY, + }); + ev.preventDefault(); +} +onSvgTouch.x0 = onSvgTouch.y0 = 0; +onSvgTouch.t0 = 0; + +/******************************************************************************/ + +function onSvgClicked(ev) { + // Unpause picker if: + // - click outside dialog AND + // - not in preview mode + if ( dom.cl.has(dom.root, 'paused') ) { + if ( dom.cl.has(dom.root, 'preview') ) { + updatePreview(false); + } + unpausePicker(); + return; + } + // Force dialog to always be visible when using a touch-driven device. + if ( ev.type === 'touch' ) { + dom.cl.add(dom.root, 'show'); + } + toolOverlay.postMessage({ + what: 'candidatesAtPoint', + mx: ev.clientX, + my: ev.clientY, + broad: ev.ctrlKey, + }).then(details => { + showDialog(details); + }); +} + +/******************************************************************************/ + +function onKeyPressed(ev) { + if ( ev.key === 'Escape' || ev.which === 27 ) { + quitPicker(); + return; + } +} + +/******************************************************************************/ + +function onMinimizeClicked() { + if ( dom.cl.has(dom.root, 'paused') === false ) { + pausePicker(); + highlightCandidate(); + return; + } + dom.cl.toggle(dom.root, 'minimized'); +} + +/******************************************************************************/ + +function onFilterTextChanged() { + highlightCandidate(); +} + +/******************************************************************************/ + +function toggleView(view, persist = false) { + dom.root.dataset.view = `${view}`; + if ( persist !== true ) { return; } + localWrite('picker.view', dom.root.dataset.view); +} + +function onViewToggled(dir) { + let view = parseInt(dom.root.dataset.view, 10); + view += dir; + if ( view < 0 ) { view = 0; } + if ( view > 2 ) { view = 2; } + toggleView(view, true); +} + +/******************************************************************************/ + +function selectorFromCandidates() { + const selectorParts = []; + let liPrevious = null; + for ( const li of qsa$('#candidateFilters li') ) { + const selector = []; + for ( const span of qsa$(li, '.on[data-part]') ) { + selector.push(span.textContent); + } + if ( selector.length !== 0 ) { + if ( liPrevious !== null ) { + if ( li.previousElementSibling === liPrevious ) { + selectorParts.unshift(' > '); + } else if ( liPrevious !== li ) { + selectorParts.unshift(' '); + } + } + liPrevious = li; + selectorParts.unshift(selector.join('')); + } + } + return selectorParts.join(''); +} + +/******************************************************************************/ + +function onSliderChanged(ev) { + updateSlider(Math.round(ev.target.valueAsNumber)); +} + +function updateSlider(i) { + if ( i === sliderPartsPos ) { return; } + sliderPartsPos = i; + dom.cl.remove('#candidateFilters [data-part]', 'on'); + const parts = sliderParts[i]; + for ( const address of parts ) { + dom.cl.add(`#candidateFilters [data-part="${address}"]`, 'on'); + } + const selector = selectorFromCandidates(); + qs$('textarea').value = selector; + highlightCandidate(); +} + +/******************************************************************************/ + +function updateElementCount(details) { + const { count, error } = details; + const span = qs$('#resultsetCount'); + if ( error ) { + span.textContent = 'Error'; + span.setAttribute('title', error); + } else { + span.textContent = count; + span.removeAttribute('title'); + } + const disabled = Boolean(count) === false ? '' : null; + dom.attr('#create', 'disabled', disabled); + updatePreview(); +} + +/******************************************************************************/ + +function onPreviewClicked() { + dom.cl.toggle(dom.root, 'preview'); + updatePreview(); +} + +function updatePreview(state) { + if ( state === undefined ) { + state = dom.cl.has(dom.root, 'preview'); + } else { + dom.cl.toggle(dom.root, 'preview', state) + } + const selector = state && validateSelector(qs$('textarea').value) || ''; + return toolOverlay.postMessage({ what: 'previewSelector', selector }); +} + +/******************************************************************************/ + +async function onCreateClicked() { + const selector = validateSelector(qs$('textarea').value); + if ( selector === undefined ) { return; } + await toolOverlay.postMessage({ what: 'terminateCustomFilters' }); + await toolOverlay.sendMessage({ + what: 'addCustomFilters', + hostname: toolOverlay.url.hostname, + selectors: [ selector ], + }); + await toolOverlay.postMessage({ what: 'startCustomFilters' }); + qs$('textarea').value = ''; + dom.cl.remove(dom.root, 'preview'); + quitPicker(); +} + +/******************************************************************************/ + +function attributeNameFromSelector(part) { + const pos = part.search(/\^?=/); + return part.slice(1, pos); +} + +/******************************************************************************/ + +function onCandidateClicked(ev) { + const target = ev.target; + if ( target.matches('[data-part]') ) { + const address = target.dataset.part; + const part = selectorPartsDB.get(parseInt(address, 10)); + if ( part.startsWith('[') ) { + if ( target.textContent === part ) { + target.textContent = `[${attributeNameFromSelector(part)}]`; + dom.cl.remove(target, 'on'); + } else if ( dom.cl.has(target, 'on') ) { + target.textContent = part; + } else { + dom.cl.add(target, 'on'); + } + } else { + dom.cl.toggle(target, 'on'); + } + } else if ( target.matches('li') ) { + if ( qs$(target, ':scope > span:not(.on)') !== null ) { + dom.cl.add(qsa$(target, ':scope > [data-part]:not(.on)'), 'on'); + } else { + dom.cl.remove(qsa$(target, ':scope > [data-part]'), 'on'); + } + } + const selector = selectorFromCandidates(); + qs$('textarea').value = selector; + highlightCandidate(); +} + +/******************************************************************************/ + +function showDialog(msg) { + pausePicker(); + + /* global */selectorPartsDB = new Map(msg.partsDB); + const { listParts } = msg; + const root = qs$('#candidateFilters'); + const ul = qs$(root, 'ul'); + while ( ul.firstChild !== null ) { + ul.firstChild.remove(); + } + for ( const parts of listParts ) { + const li = document.createElement('li'); + for ( const address of parts ) { + const span = document.createElement('span'); + const part = selectorPartsDB.get(address); + span.dataset.part = address; + if ( part.startsWith('[') ) { + span.textContent = `[${attributeNameFromSelector(part)}]`; + } else { + span.textContent = part; + } + li.append(span); + } + ul.appendChild(li); + } + + /* global */sliderParts = msg.sliderParts; + /* global */sliderPartsPos = -1; + const slider = qs$('#slider'); + const last = sliderParts.length - 1; + dom.attr(slider, 'max', last); + dom.attr(slider, 'value', last); + dom.attr(slider, 'disabled', last !== 0 ? null : ''); + slider.value = last; + updateSlider(last); +} + +/******************************************************************************/ + +function highlightCandidate() { + const selector = validateSelector(qs$('textarea').value); + if ( selector === undefined ) { + toolOverlay.postMessage({ what: 'unhighlight' }); + updateElementCount({ count: 0, error: validateSelector.error }); + return; + } + toolOverlay.postMessage({ + what: 'highlightFromSelector', + selector, + }).then(result => { + updateElementCount(result); + }); +} + +/******************************************************************************* + * + * paused: + * - select element mode disabled + * - preview mode enabled or disabled + * - dialog unminimized + * + * unpaused: + * - select element mode enabled + * - preview mode disabled + * - dialog minimized + * + * */ + +function pausePicker() { + dom.cl.add(dom.root, 'paused'); + dom.cl.remove(dom.root, 'minimized'); + toolOverlay.highlightElementUnderMouse(false); +} + +function unpausePicker() { + dom.cl.remove(dom.root, 'paused', 'preview'); + dom.cl.add(dom.root, 'minimized'); + updatePreview(false); + toolOverlay.highlightElementUnderMouse(true); +} + +/******************************************************************************/ + +function startPicker() { + toolOverlay.postMessage({ what: 'startTool' }); + + localRead('picker.view').then(value => { + if ( Boolean(value) === false ) { return; } + toggleView(value); + }); + + self.addEventListener('keydown', onKeyPressed, true); + dom.on('svg#overlay', 'click', onSvgClicked); + dom.on('svg#overlay', 'touchstart', onSvgTouch, { passive: true }); + dom.on('svg#overlay', 'touchend', onSvgTouch); + dom.on('#minimize', 'click', onMinimizeClicked); + dom.on('textarea', 'input', onFilterTextChanged); + dom.on('#quit', 'click', quitPicker); + dom.on('#slider', 'input', onSliderChanged); + dom.on('#pick', 'click', resetPicker); + dom.on('#preview', 'click', onPreviewClicked); + dom.on('#moreOrLess > span:first-of-type', 'click', ( ) => { onViewToggled(1); }); + dom.on('#moreOrLess > span:last-of-type', 'click', ( ) => { onViewToggled(-1); }); + dom.on('#create', 'click', ( ) => { onCreateClicked(); }); + dom.on('#candidateFilters ul', 'click', onCandidateClicked); + toolOverlay.highlightElementUnderMouse(true); +} + +/******************************************************************************/ + +function quitPicker() { + updatePreview(false); + toolOverlay.stop(); +} + +/******************************************************************************/ + +function resetPicker() { + toolOverlay.postMessage({ what: 'unhighlight' }); + unpausePicker(); +} + +/******************************************************************************/ + +function onMessage(msg) { + switch ( msg.what ) { + case 'startTool': + startPicker(); + break; + default: + break; + } +} + +/******************************************************************************/ + +// Wait for the content script to establish communication +toolOverlay.start(onMessage); + +/******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/popup.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/popup.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/popup.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/popup.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,15 +19,9 @@ Home: https://github.com/gorhill/uBlock */ -import { - browser, - localRead, localWrite, - runtime, - sendMessage, -} from './ext.js'; - +import { browser, runtime, sendMessage } from './ext.js'; import { dom, qs$ } from './dom.js'; -import { i18n, i18n$ } from './i18n.js'; +import { i18n$ } from './i18n.js'; import punycode from './punycode.js'; /******************************************************************************/ @@ -38,12 +32,6 @@ /******************************************************************************/ -function normalizedHostname(hn) { - return hn.replace(/^www\./, ''); -} - -/******************************************************************************/ - function renderAdminRules() { const { disabledFeatures: forbid = [] } = popupPanelData; if ( forbid.length === 0 ) { return; } @@ -69,17 +57,27 @@ async function commitFilteringMode() { if ( tabURL.hostname === '' ) { return; } - const targetHostname = normalizedHostname(tabURL.hostname); + const targetHostname = tabURL.hostname; const modeSlider = qs$('.filteringModeSlider'); const afterLevel = parseInt(modeSlider.dataset.level, 10); const beforeLevel = parseInt(modeSlider.dataset.levelBefore, 10); if ( afterLevel > 1 ) { + if ( beforeLevel <= 1 ) { + sendMessage({ + what: 'setPendingFilteringMode', + tabId: currentTab.id, + url: tabURL.href, + hostname: targetHostname, + beforeLevel, + afterLevel, + }); + } let granted = false; try { granted = await browser.permissions.request({ origins: [ `*://*.${targetHostname}/*` ], }); - } catch(ex) { + } catch { } if ( granted !== true ) { setFilteringMode(beforeLevel); @@ -99,10 +97,13 @@ setFilteringMode(actualLevel); } if ( actualLevel !== beforeLevel && popupPanelData.autoReload ) { + const justReload = tabURL.href === currentTab.url; self.setTimeout(( ) => { - browser.tabs.update(currentTab.id, { - url: tabURL.href, - }); + if ( justReload ) { + browser.tabs.reload(currentTab.id); + } else { + browser.tabs.update(currentTab.id, { url: tabURL.href }); + } }, 437); } } @@ -188,90 +189,31 @@ } ); -dom.on( - '.filteringModeSlider', - 'mouseenter', - '.filteringModeSlider span[data-level]', - ev => { - const span = ev.target; - const level = parseInt(span.dataset.level, 10); - dom.text( - '#filteringModeText > span:nth-of-type(2)', - i18n$(`filteringMode${level}Name`) - ); - } -); - -dom.on( - '.filteringModeSlider', - 'mouseleave', - '.filteringModeSlider span[data-level]', - ( ) => { - dom.text('#filteringModeText > span:nth-of-type(2)', ''); - } -); - -/******************************************************************************/ - -// The popup panel is made of sections. Visibility of sections can be -// toggled on/off. - -const maxNumberOfSections = 2; - -const sectionBitsFromAttribute = function() { - const value = dom.body.dataset.section; - if ( value === '' ) { return 0; } - let bits = 0; - for ( const c of value.split(' ') ) { - bits |= 1 << (c.charCodeAt(0) - 97); - } - return bits; -}; - -const sectionBitsToAttribute = function(bits) { - if ( typeof bits !== 'number' ) { return; } - if ( isNaN(bits) ) { return; } - const value = []; - for ( let i = 0; i < maxNumberOfSections; i++ ) { - const bit = 1 << i; - if ( (bits & bit) === 0 ) { continue; } - value.push(String.fromCharCode(97 + i)); - } - dom.body.dataset.section = value.join(' '); -}; +if ( dom.cl.has(dom.html, 'mobile') === false ) { + dom.on('.filteringModeSlider', + 'mouseenter', + '.filteringModeSlider span[data-level]', + ev => { + const span = ev.target; + const level = parseInt(span.dataset.level, 10); + dom.text('#filteringModeText > span:nth-of-type(2)', + i18n$(`filteringMode${level}Name`) + ); + } + ); -async function toggleSections(more) { - let currentBits = sectionBitsFromAttribute(); - let newBits = currentBits; - for ( let i = 0; i < maxNumberOfSections; i++ ) { - const bit = 1 << (more ? i : maxNumberOfSections - i - 1); - if ( more ) { - newBits |= bit; - } else { - newBits &= ~bit; + dom.on('.filteringModeSlider', + 'mouseleave', + '.filteringModeSlider span[data-level]', + ( ) => { + dom.text('#filteringModeText > span:nth-of-type(2)', ''); } - if ( newBits !== currentBits ) { break; } - } - if ( newBits === currentBits ) { return; } - sectionBitsToAttribute(newBits); - localWrite('popupPanelSections', newBits); + ); } -localRead('popupPanelSections').then(bits => { - sectionBitsToAttribute(bits || 0); -}); - -dom.on('#moreButton', 'click', ( ) => { - toggleSections(true); -}); - -dom.on('#lessButton', 'click', ( ) => { - toggleSections(false); -}); - /******************************************************************************/ -dom.on('#showMatchedRules', 'click', ev => { +dom.on('#gotoMatchedRules', 'click', ev => { if ( ev.isTrusted !== true ) { return; } if ( ev.button !== 0 ) { return; } sendMessage({ @@ -282,16 +224,16 @@ /******************************************************************************/ -dom.on('[data-i18n-title="popupTipReport"]', 'click', ev => { +dom.on('#gotoReport', 'click', ev => { if ( ev.isTrusted !== true ) { return; } let url; try { url = new URL(currentTab.url); - } catch(_) { + } catch { } if ( url === undefined ) { return; } const reportURL = new URL(runtime.getURL('/report.html')); - reportURL.searchParams.set('url', url.href); + reportURL.searchParams.set('url', tabURL.href); reportURL.searchParams.set('mode', popupPanelData.level); sendMessage({ what: 'gotoURL', @@ -301,7 +243,7 @@ /******************************************************************************/ -dom.on('[data-i18n-title="popupTipDashboard"]', 'click', ev => { +dom.on('#gotoDashboard', 'click', ev => { if ( ev.isTrusted !== true ) { return; } if ( ev.button !== 0 ) { return; } runtime.openOptionsPage(); @@ -309,6 +251,46 @@ /******************************************************************************/ +dom.on('#gotoZapper', 'click', ( ) => { + if ( browser.scripting === undefined ) { return; } + browser.scripting.executeScript({ + files: [ '/js/scripting/tool-overlay.js', '/js/scripting/zapper.js' ], + target: { tabId: currentTab.id }, + }); + self.close(); +}); + +/******************************************************************************/ + +dom.on('#gotoPicker', 'click', ( ) => { + if ( browser.scripting === undefined ) { return; } + browser.scripting.executeScript({ + files: [ + '/js/scripting/css-procedural-api.js', + '/js/scripting/tool-overlay.js', + '/js/scripting/picker.js', + ], + target: { tabId: currentTab.id }, + }); + self.close(); +}); + +/******************************************************************************/ + +dom.on('#gotoUnpicker', 'click', ( ) => { + if ( browser.scripting === undefined ) { return; } + browser.scripting.executeScript({ + files: [ + '/js/scripting/tool-overlay.js', + '/js/scripting/unpicker.js', + ], + target: { tabId: currentTab.id }, + }); + self.close(); +}); + +/******************************************************************************/ + async function init() { const [ tab ] = await browser.tabs.query({ active: true, @@ -325,14 +307,15 @@ url = new URL(url.hash.slice(1)); } tabURL.href = url.href || ''; - } catch(ex) { + } catch { + return false; } if ( url !== undefined ) { const response = await sendMessage({ what: 'popupPanelData', origin: url.origin, - hostname: normalizedHostname(tabURL.hostname), + hostname: tabURL.hostname, }); if ( response instanceof Object ) { Object.assign(popupPanelData, response); @@ -345,47 +328,17 @@ dom.text('#hostname', punycode.toUnicode(tabURL.hostname)); - dom.cl.toggle('#showMatchedRules', 'enabled', + dom.cl.toggle('#gotoMatchedRules', 'enabled', popupPanelData.isSideloaded === true && popupPanelData.developerMode && typeof currentTab.id === 'number' && isNaN(currentTab.id) === false ); - dom.cl.toggle('#reportFilterIssue', 'enabled', - /^https?:\/\//.test(url?.href) - ); - - const parent = qs$('#rulesetStats'); - for ( const details of popupPanelData.rulesetDetails || [] ) { - const div = dom.clone('#templates .rulesetDetails'); - qs$(div, 'h1').append(i18n.patchUnicodeFlags(details.name)); - const { rules, filters, css } = details; - let ruleCount = rules.plain + rules.regex; - if ( popupPanelData.hasOmnipotence ) { - ruleCount += rules.removeparam + rules.redirect + rules.modifyHeaders; - } - let specificCount = 0; - if ( typeof css.specific === 'number' ) { - specificCount += css.specific; - } - if ( typeof css.declarative === 'number' ) { - specificCount += css.declarative; - } - if ( typeof css.procedural === 'number' ) { - specificCount += css.procedural; - } - dom.text( - qs$(div, 'p'), - i18n$('perRulesetStats') - .replace('{{ruleCount}}', ruleCount.toLocaleString()) - .replace('{{filterCount}}', filters.accepted.toLocaleString()) - .replace('{{cssSpecificCount}}', specificCount.toLocaleString()) - ); - parent.append(div); - } + const isHTTP = url.protocol === 'http:' || url.protocol === 'https:'; + dom.cl.toggle(dom.root, 'isHTTP', isHTTP); - dom.cl.remove(dom.body, 'loading'); + dom.cl.toggle('#gotoUnpicker', 'enabled', popupPanelData.hasCustomFilters); return true; } @@ -393,8 +346,10 @@ async function tryInit() { try { await init(); - } catch(ex) { + } catch { setTimeout(tryInit, 100); + } finally { + dom.cl.remove(dom.body, 'loading'); } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/report.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/report.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/report.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/report.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,8 @@ Home: https://github.com/gorhill/uBlock */ -import { dnr, runtime } from './ext.js'; import { dom, qs$ } from './dom.js'; +import { getTroubleshootingInfo } from './troubleshooting.js'; import { sendMessage } from './ext.js'; /******************************************************************************/ @@ -52,7 +52,7 @@ hostname: parsedURL.hostname.replace(/^(m|mobile|www)\./, ''), mode: url.searchParams.get('mode'), }; - } catch(ex) { + } catch { } return null; })(); @@ -65,32 +65,6 @@ /******************************************************************************/ -function renderData(data, depth = 0) { - const indent = ' '.repeat(depth); - if ( Array.isArray(data) ) { - const out = []; - for ( const value of data ) { - out.push(renderData(value, depth)); - } - return out.join('\n'); - } - if ( typeof data !== 'object' || data === null ) { - return `${indent}${data}`; - } - const out = []; - for ( const [ name, value ] of Object.entries(data) ) { - if ( typeof value === 'object' && value !== null ) { - out.push(`${indent}${name}:`); - out.push(renderData(value, depth + 1)); - continue; - } - out.push(`${indent}${name}: ${value}`); - } - return out.join('\n'); -} - -/******************************************************************************/ - async function reportSpecificFilterIssue() { const githubURL = new URL( 'https://github.com/uBlockOrigin/uAssets/issues/new?template=specific_report_from_ubol.yml' @@ -107,18 +81,9 @@ ); githubURL.searchParams.set('category', issueType); - const manifest = runtime.getManifest(); - const rulesets = await dnr.getEnabledRulesets(); - const defaultMode = await sendMessage({ what: 'getDefaultFilteringMode' }); - const modes = [ 'no filtering', 'basic', 'optimal', 'complete' ]; - const config = { - version: `uBOL ${manifest.version}`, - mode: `${modes[reportedPage.mode]} / ${modes[defaultMode]}`, - rulesets, - }; const configBody = [ '```yaml', - renderData(config), + qs$('[data-i18n="supportS5H"] + pre').textContent, '```', '', ].join('\n'); @@ -128,7 +93,9 @@ /******************************************************************************/ -(async ( ) => { +getTroubleshootingInfo(reportedPage.mode).then(config => { + qs$('[data-i18n="supportS5H"] + pre').textContent = config; + dom.on('[data-url]', 'click', ev => { const elem = ev.target.closest('[data-url]'); const url = dom.attr(elem, 'data-url'); @@ -150,5 +117,4 @@ ev.preventDefault(); }); } - -})(); +}); diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/ro-dnr-editor.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/ro-dnr-editor.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/ro-dnr-editor.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/ro-dnr-editor.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,104 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2014-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { runtime, sendMessage } from './ext.js'; +import { DNREditor } from './dnr-editor.js'; +import { i18n$ } from './i18n.js'; +import { normalizeDNRRules } from './ext-compat.js'; +import { textFromRules } from './dnr-parser.js'; + +/******************************************************************************/ + +export class ReadOnlyDNREditor extends DNREditor { + async getText(hint) { + if ( hint === 'dnr.ro.dynamic' ) { + const rules = await sendMessage({ what: 'getEffectiveDynamicRules' }); + if ( Array.isArray(rules) === false ) { return; } + this.id = 'dynamic'; + this.count = rules.length; + return textFromRules(rules, { keepId: true }); + } + if ( hint === 'dnr.ro.session' ) { + const rules = await sendMessage({ what: 'getEffectiveSessionRules' }); + if ( Array.isArray(rules) === false ) { return; } + this.id = 'session'; + this.count = rules.length; + return textFromRules(rules, { keepId: true }); + } + const match = /^dnr\.ro\.(.+)$/.exec(hint); + if ( match === null ) { return; } + this.id = match[1]; + const allRulesetDetails = await sendMessage({ what: 'getRulesetDetails' }); + const rulesetDetails = allRulesetDetails.find(a => a.id === this.id); + if ( rulesetDetails === undefined ) { return; } + const manifestRulesets = runtime.getManifest().declarative_net_request.rule_resources; + const mainPathMap = new Map( + manifestRulesets.map(({ id, path }) => [ id, path ]) + ); + const realms = { + plain: 'main', + regex: 'regex', + }; + const promises = []; + for ( const [ realm, dir ] of Object.entries(realms) ) { + if ( Boolean(rulesetDetails.rules?.[realm]) === false ) { continue; } + const url = dir === 'main' + ? mainPathMap.get(this.id) + : `./rulesets/${dir}/${this.id}.json`; + promises.push( + fetch(url).then(response => + response.json() + ).then(rules => + normalizeDNRRules(rules) + ) + ); + } + const parts = await Promise.all(promises); + const allRules = []; + for ( const rules of parts ) { + for ( const rule of rules ) { + allRules.push(rule); + } + } + this.count = allRules.length; + return textFromRules(allRules, { keepId: true }); + } + + on(editor) { + if ( typeof this.count !== 'number' ) { + return editor.updateSummaryPanel(null); + } + const template = document.querySelector('template.ro-summary-panel'); + const fragment = template.content.cloneNode(true); + const root = fragment.querySelector('.summary-panel'); + root.textContent = i18n$('dnrRulesCountInfo') + .replace('{count}', (this.count || 0).toLocaleString()) + editor.updateSummaryPanel(root); + } + + off(editor) { + editor.updateSummaryPanel(null); + } + + exportToFile(text) { + return super.exportToFile(text, `${this.id}-dnr-ruleset.json`); + } +}; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/ruleset-manager.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/ruleset-manager.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/ruleset-manager.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/ruleset-manager.js 2025-10-25 19:32:51.000000000 +0000 @@ -20,38 +20,53 @@ */ import { - TAB_ID_NONE, - browser, - dnr, i18n, localRead, localRemove, localWrite, runtime, sessionRead, sessionRemove, sessionWrite, + webextFlavor, } from './ext.js'; import { rulesetConfig, saveRulesetConfig, } from './config.js'; +import { ubolErr, ubolLog } from './debug.js'; - +import { dnr } from './ext-compat.js'; import { fetchJSON } from './fetch.js'; import { getAdminRulesets } from './admin.js'; -import { ubolLog } from './debug.js'; +import { hasBroadHostPermissions } from './utils.js'; +import { rulesFromText } from './dnr-parser.js'; /******************************************************************************/ +const SPECIAL_RULES_REALM = 5000000; +const USER_RULES_BASE_RULE_ID = 9000000; +const USER_RULES_PRIORITY = 1000000; const TRUSTED_DIRECTIVE_BASE_RULE_ID = 8000000; +const TRUSTED_DIRECTIVE_PRIORITY = USER_RULES_PRIORITY + 1000000; const STRICTBLOCK_PRIORITY = 29; +let dynamicRegexCount = 0; +let sessionRegexCount = 0; + /******************************************************************************/ const isStrictBlockRule = rule => { if ( rule.priority !== STRICTBLOCK_PRIORITY ) { return false; } - if ( rule.action.type !== 'redirect' ) { return false; } - const substitution = rule.action.redirect.regexSubstitution; - return substitution !== undefined && - substitution.includes('/strictblock.'); + if ( rule.condition?.resourceTypes === undefined ) { return false; } + if ( rule.condition.resourceTypes.length !== 1 ) { return false; } + if ( rule.condition.resourceTypes[0] !== 'main_frame' ) { return false; } + if ( rule.action.type === 'redirect' ) { + const substitution = rule.action.redirect.regexSubstitution; + return substitution !== undefined && + substitution.includes('/strictblock.'); + } + if ( rule.action.type === 'allow' ) { + return Array.isArray(rule.condition?.requestDomains); + } + return false; }; /******************************************************************************/ @@ -60,26 +75,22 @@ if ( getRulesetDetails.rulesetDetailsPromise !== undefined ) { return getRulesetDetails.rulesetDetailsPromise; } - getRulesetDetails.rulesetDetailsPromise = fetchJSON('/rulesets/ruleset-details').then(entries => { - const rulesMap = new Map( - entries.map(entry => [ entry.id, entry ]) - ); - return rulesMap; - }); + getRulesetDetails.rulesetDetailsPromise = + fetchJSON('/rulesets/ruleset-details').then(entries => { + const rulesMap = new Map(entries.map(entry => [ entry.id, entry ])); + return rulesMap; + }); return getRulesetDetails.rulesetDetailsPromise; } /******************************************************************************/ -async function pruneInvalidRegexRules(realm, rulesIn) { - const rejectedRegexRules = []; - +async function pruneInvalidRegexRules(realm, rulesIn, rejected = []) { const validateRegex = regex => { return dnr.isRegexSupported({ regex, isCaseSensitive: false }).then(result => { - const isSupported = result?.isSupported || false; - pruneInvalidRegexRules.validated.set(regex, isSupported); - if ( isSupported ) { return true; } - rejectedRegexRules.push(`\t${regex} ${result?.reason}`); + pruneInvalidRegexRules.validated.set(regex, result?.reason || true); + if ( result.isSupported ) { return true; } + rejected.push({ regex, reason: result?.reason }); return false; }); }; @@ -92,8 +103,11 @@ continue; } const { regexFilter } = rule.condition; - if ( pruneInvalidRegexRules.validated.has(regexFilter) ) { - toCheck.push(pruneInvalidRegexRules.validated.get(regexFilter)); + const reason = pruneInvalidRegexRules.validated.get(regexFilter); + if ( reason !== undefined ) { + toCheck.push(reason === true); + if ( reason === true ) { continue; } + rejected.push({ regex: regexFilter, reason }); continue; } toCheck.push(validateRegex(regexFilter)); @@ -102,9 +116,9 @@ // Collate results const isValid = await Promise.all(toCheck); - if ( rejectedRegexRules.length !== 0 ) { + if ( rejected.length !== 0 ) { ubolLog(`${realm} realm: rejected regexes:\n`, - rejectedRegexRules.join('\n') + rejected.map(e => `${e.regex} → ${e.reason}`).join('\n') ); } @@ -117,8 +131,8 @@ async function updateRegexRules(currentRules, addRules, removeRuleIds) { // Remove existing regex-related block rules for ( const rule of currentRules ) { - const { type } = rule.action; - if ( type !== 'block' && type !== 'allow' ) { continue; } + if ( rule.id === 0 ) { continue; } + if ( rule.id >= SPECIAL_RULES_REALM ) { continue; } if ( rule.condition.regexFilter === undefined ) { continue; } removeRuleIds.push(rule.id); } @@ -152,183 +166,64 @@ /******************************************************************************/ -async function updateRemoveparamRules(currentRules, addRules, removeRuleIds) { - // Remove existing removeparam-related rules - for ( const rule of currentRules ) { - if ( rule.action.type !== 'redirect' ) { continue; } - if ( rule.action.redirect.transform === undefined ) { continue; } - removeRuleIds.push(rule.id); - } - - const [ - hasOmnipotence, - rulesetDetails, - ] = await Promise.all([ - browser.permissions.contains({ origins: [ '' ] }), - getEnabledRulesetsDetails(), - ]); - - // Fetch removeparam rules for all enabled rulesets - const toFetch = []; - for ( const details of rulesetDetails ) { - if ( details.rules.removeparam === 0 ) { continue; } - toFetch.push(fetchJSON(`/rulesets/removeparam/${details.id}`)); - } - const removeparamRulesets = await Promise.all(toFetch); - - // Removeparam rules can only be enforced with omnipotence - const allRules = []; - if ( hasOmnipotence ) { - for ( const rules of removeparamRulesets ) { - if ( Array.isArray(rules) === false ) { continue; } - for ( const rule of rules ) { - allRules.push(rule); - } - } - } - if ( allRules.length === 0 ) { return; } - - const validRules = await pruneInvalidRegexRules('removeparam', allRules); - if ( validRules.length === 0 ) { return; } - - ubolLog(`Add ${validRules.length} DNR removeparam rules`); - addRules.push(...validRules); -} - -/******************************************************************************/ +async function updateDynamicRules() { + const currentRules = await dnr.getDynamicRules(); + const addRules = []; + const removeRuleIds = []; -async function updateRedirectRules(currentRules, addRules, removeRuleIds) { - // Remove existing redirect-related rules + // Remove potentially left-over rules from previous version for ( const rule of currentRules ) { - if ( rule.action.type !== 'redirect' ) { continue; } - if ( rule.action.redirect.extensionPath === undefined ) { continue; } + if ( rule.id >= SPECIAL_RULES_REALM ) { continue; } removeRuleIds.push(rule.id); + rule.id = 0; } - const [ - hasOmnipotence, - rulesetDetails, - ] = await Promise.all([ - browser.permissions.contains({ origins: [ '' ] }), - getEnabledRulesetsDetails(), - ]); - - // Fetch redirect rules for all enabled rulesets - const toFetch = []; - for ( const details of rulesetDetails ) { - if ( details.rules.redirect === 0 ) { continue; } - toFetch.push(fetchJSON(`/rulesets/redirect/${details.id}`)); - } - const redirectRulesets = await Promise.all(toFetch); + await updateRegexRules(currentRules, addRules, removeRuleIds); + if ( addRules.length === 0 && removeRuleIds.length === 0 ) { return; } - // Redirect rules can only be enforced with omnipotence - const allRules = []; - if ( hasOmnipotence ) { - for ( const rules of redirectRulesets ) { - if ( Array.isArray(rules) === false ) { continue; } - for ( const rule of rules ) { - allRules.push(rule); - } - } + dynamicRegexCount = 0; + let ruleId = 1; + for ( const rule of addRules ) { + if ( rule?.condition.regexFilter ) { dynamicRegexCount += 1; } + rule.id = ruleId++; } - if ( allRules.length === 0 ) { return; } - - const validRules = await pruneInvalidRegexRules('redirect', allRules); - if ( validRules.length === 0 ) { return; } - - ubolLog(`Add ${validRules.length} DNR redirect rules`); - addRules.push(...validRules); -} - -/******************************************************************************/ - -async function updateModifyHeadersRules(currentRules, addRules, removeRuleIds) { - // Remove existing header modification-related rules - for ( const rule of currentRules ) { - if ( rule.action.type !== 'modifyHeaders' ) { continue; } - removeRuleIds.push(rule.id); + if ( dynamicRegexCount !== 0 ) { + ubolLog(`Using ${dynamicRegexCount}/${dnr.MAX_NUMBER_OF_REGEX_RULES} dynamic regex-based DNR rules`); } - const [ - hasOmnipotence, - rulesetDetails, - ] = await Promise.all([ - browser.permissions.contains({ origins: [ '' ] }), - getEnabledRulesetsDetails(), - ]); - - // Fetch modifyHeaders rules for all enabled rulesets - const toFetch = []; - for ( const details of rulesetDetails ) { - if ( details.rules.modifyHeaders === 0 ) { continue; } - toFetch.push(fetchJSON(`/rulesets/modify-headers/${details.id}`)); - } - const rulesets = await Promise.all(toFetch); + const response = {}; - // Redirect rules can only be enforced with omnipotence - const allRules = []; - if ( hasOmnipotence ) { - for ( const rules of rulesets ) { - if ( Array.isArray(rules) === false ) { continue; } - for ( const rule of rules ) { - allRules.push(rule); - } + try { + await dnr.updateDynamicRules({ addRules, removeRuleIds }); + if ( removeRuleIds.length !== 0 ) { + ubolLog(`Remove ${removeRuleIds.length} dynamic DNR rules`); + } + if ( addRules.length !== 0 ) { + ubolLog(`Add ${addRules.length} dynamic DNR rules`); } + } catch(reason) { + ubolErr(`updateDynamicRules/${reason}`); + response.error = `${reason}`; } - if ( allRules.length === 0 ) { return; } - const validRules = await pruneInvalidRegexRules('modify-headers', allRules); - if ( validRules.length === 0 ) { return; } + const result = await updateSessionRules(); + if ( result?.error ) { + response.error ||= result.error; + } - ubolLog(`Add ${validRules.length} DNR modify-headers rules`); - addRules.push(...validRules); + return response; } /******************************************************************************/ -async function updateDynamicRules() { - const currentRules = await dnr.getDynamicRules(); - const addRules = []; - const removeRuleIds = []; - - // Remove potentially left-over strict-block rules from previous version - for ( const rule of currentRules ) { - if ( isStrictBlockRule(rule) === false ) { continue; } - removeRuleIds.push(rule.id); - } - - await Promise.all([ - updateRegexRules(currentRules, addRules, removeRuleIds), - updateRemoveparamRules(currentRules, addRules, removeRuleIds), - updateRedirectRules(currentRules, addRules, removeRuleIds), - updateModifyHeadersRules(currentRules, addRules, removeRuleIds), - ]); - if ( addRules.length === 0 && removeRuleIds.length === 0 ) { return; } - - const maxRegexRuleCount = dnr.MAX_NUMBER_OF_REGEX_RULES; - let regexRuleCount = 0; - let ruleId = 1; - for ( const rule of addRules ) { - if ( rule?.condition.regexFilter ) { regexRuleCount += 1; } - if ( (rule.id || 0) >= TRUSTED_DIRECTIVE_BASE_RULE_ID ) { continue; } - rule.id = ruleId++; - } - if ( regexRuleCount !== 0 ) { - ubolLog(`Using ${regexRuleCount}/${maxRegexRuleCount} dynamic regex-based DNR rules`); +async function getEffectiveDynamicRules() { + const allRules = await dnr.getDynamicRules(); + const dynamicRules = []; + for ( const rule of allRules ) { + if ( rule.id >= USER_RULES_BASE_RULE_ID ) { continue; } + dynamicRules.push(rule); } - return Promise.all([ - dnr.updateDynamicRules({ addRules, removeRuleIds }).then(( ) => { - if ( removeRuleIds.length !== 0 ) { - ubolLog(`Remove ${removeRuleIds.length} dynamic DNR rules`); - } - if ( addRules.length !== 0 ) { - ubolLog(`Add ${addRules.length} dynamic DNR rules`); - } - }).catch(reason => { - console.error(`updateDynamicRules() / ${reason}`); - }), - updateSessionRules(), - ]); + return dynamicRules; } /******************************************************************************/ @@ -342,13 +237,18 @@ if ( rulesetConfig.strictBlockMode === false ) { return; } + // https://github.com/uBlockOrigin/uBOL-home/issues/428#issuecomment-3172663563 + // https://bugs.webkit.org/show_bug.cgi?id=298199 + // https://developer.apple.com/forums/thread/756214 + if ( webextFlavor === 'safari' ) { return; } + const [ hasOmnipotence, rulesetDetails, permanentlyExcluded = [], temporarilyExcluded = [], ] = await Promise.all([ - browser.permissions.contains({ origins: [ '' ] }), + hasBroadHostPermissions(), getEnabledRulesetsDetails(), localRead('excludedStrictBlockHostnames'), sessionRead('excludedStrictBlockHostnames'), @@ -383,12 +283,13 @@ if ( validRules.length === 0 ) { return; } ubolLog(`Add ${validRules.length} DNR strictblock rules`); for ( const rule of validRules ) { + rule.priority = STRICTBLOCK_PRIORITY; addRules.push(rule); } const allExcluded = permanentlyExcluded.concat(temporarilyExcluded); if ( allExcluded.length === 0 ) { return; } - addRules.push({ + addRules.unshift({ action: { type: 'allow' }, condition: { requestDomains: allExcluded, @@ -409,9 +310,11 @@ return updateSessionRules(); } -async function setStrictBlockMode(state) { +async function setStrictBlockMode(state, force = false) { const newState = Boolean(state); - if ( newState === rulesetConfig.strictBlockMode ) { return; } + if ( force === false ) { + if ( newState === rulesetConfig.strictBlockMode ) { return; } + } rulesetConfig.strictBlockMode = newState; const promises = [ saveRulesetConfig() ]; if ( newState === false ) { @@ -427,156 +330,86 @@ /******************************************************************************/ async function updateSessionRules() { - const addRules = []; + const addRulesUnfiltered = []; const removeRuleIds = []; const currentRules = await dnr.getSessionRules(); - await updateStrictBlockRules(currentRules, addRules, removeRuleIds); - if ( addRules.length === 0 && removeRuleIds.length === 0 ) { return; } - const maxRegexRuleCount = dnr.MAX_NUMBER_OF_REGEX_RULES; - let regexRuleCount = 0; + await updateStrictBlockRules(currentRules, addRulesUnfiltered, removeRuleIds); + if ( addRulesUnfiltered.length === 0 && removeRuleIds.length === 0 ) { return; } + const maxRegexCount = dnr.MAX_NUMBER_OF_REGEX_RULES * 0.80; + let regexCount = dynamicRegexCount; let ruleId = 1; - for ( const rule of addRules ) { - if ( rule?.condition.regexFilter ) { regexRuleCount += 1; } - rule.id = ruleId++; - } - if ( regexRuleCount !== 0 ) { - ubolLog(`Using ${regexRuleCount}/${maxRegexRuleCount} session regex-based DNR rules`); - } - return dnr.updateSessionRules({ addRules, removeRuleIds }).then(( ) => { + for ( const rule of addRulesUnfiltered ) { + if ( rule?.condition.regexFilter ) { regexCount += 1; } + rule.id = regexCount < maxRegexCount ? ruleId++ : 0; + } + sessionRegexCount = regexCount - dynamicRegexCount; + const addRules = addRulesUnfiltered.filter(a => a.id !== 0); + const rejectedRuleCount = addRulesUnfiltered.length - addRules.length; + if ( rejectedRuleCount !== 0 ) { + ubolLog(`Too many regex-based filters, ${rejectedRuleCount} session rules dropped`); + } + if ( sessionRegexCount !== 0 ) { + ubolLog(`Using ${sessionRegexCount}/${dnr.MAX_NUMBER_OF_REGEX_RULES} session regex-based DNR rules`); + } + const response = {}; + try { + await dnr.updateSessionRules({ addRules, removeRuleIds }); if ( removeRuleIds.length !== 0 ) { ubolLog(`Remove ${removeRuleIds.length} session DNR rules`); } if ( addRules.length !== 0 ) { ubolLog(`Add ${addRules.length} session DNR rules`); } - }).catch(reason => { - console.error(`updateSessionRules() / ${reason}`); - }); + } catch(reason) { + ubolErr(`updateSessionRules/${reason}`); + response.error = `${reason}`; + } + return response; } /******************************************************************************/ -async function filteringModesToDNR(modes) { - const [ - dynamicRules, - sessionRules, - ] = await Promise.all([ - dnr.getDynamicRules({ ruleIds: [ TRUSTED_DIRECTIVE_BASE_RULE_ID+0 ] }), - dnr.getSessionRules({ ruleIds: [ TRUSTED_DIRECTIVE_BASE_RULE_ID+1 ] }), - ]); - const dynamicRule = dynamicRules?.length && dynamicRules[0] || undefined; - const beforeRequestDomainSet = new Set(dynamicRule?.condition.requestDomains); - const beforeExcludedRrequestDomainSet = new Set(dynamicRule?.condition.excludedRequestDomains); - if ( dynamicRule !== undefined && beforeRequestDomainSet.size === 0 ) { - beforeRequestDomainSet.add('all-urls'); - } else { - beforeExcludedRrequestDomainSet.add('all-urls'); +async function getEffectiveSessionRules() { + const allRules = await dnr.getSessionRules(); + const sessionRules = []; + for ( const rule of allRules ) { + if ( rule.id >= USER_RULES_BASE_RULE_ID ) { continue; } + sessionRules.push(rule); } + return sessionRules; +} + +/******************************************************************************/ +async function filteringModesToDNR(modes) { const noneHostnames = new Set([ ...modes.none ]); const notNoneHostnames = new Set([ ...modes.basic, ...modes.optimal, ...modes.complete ]); - let afterRequestDomainSet = new Set(); - let afterExcludedRequestDomainSet = new Set(); - if ( noneHostnames.has('all-urls') ) { - afterRequestDomainSet = new Set([ 'all-urls' ]); - afterExcludedRequestDomainSet = notNoneHostnames; + const requestDomains = []; + const excludedRequestDomains = []; + const allowEverywhere = noneHostnames.has('all-urls'); + if ( allowEverywhere ) { + excludedRequestDomains.push(...notNoneHostnames); } else { - afterRequestDomainSet = noneHostnames; - afterExcludedRequestDomainSet = new Set(); - } - - const removeDynamicRuleIds = []; - const removeSessionRuleIds = []; - if ( dynamicRule ) { - removeDynamicRuleIds.push(TRUSTED_DIRECTIVE_BASE_RULE_ID+0); - removeSessionRuleIds.push(TRUSTED_DIRECTIVE_BASE_RULE_ID+1); - } - - const allowEverywhere = afterRequestDomainSet.delete('all-urls'); - const addDynamicRules = []; - const addSessionRules = []; - if ( - allowEverywhere || - afterRequestDomainSet.size !== 0 || - afterExcludedRequestDomainSet.size !== 0 - ) { - const rule0 = { - id: TRUSTED_DIRECTIVE_BASE_RULE_ID+0, - action: { type: 'allowAllRequests' }, - condition: { - resourceTypes: [ 'main_frame' ], - }, - priority: 100, - }; - if ( afterRequestDomainSet.size !== 0 ) { - rule0.condition.requestDomains = - Array.from(afterRequestDomainSet).sort(); - } else if ( afterExcludedRequestDomainSet.size !== 0 ) { - rule0.condition.excludedRequestDomains = - Array.from(afterExcludedRequestDomainSet).sort(); - } - addDynamicRules.push(rule0); - // https://github.com/uBlockOrigin/uBOL-home/issues/114 - // https://github.com/uBlockOrigin/uBOL-home/issues/247 - const rule1 = { - id: TRUSTED_DIRECTIVE_BASE_RULE_ID+1, - action: { type: 'allow' }, - condition: { - tabIds: [ TAB_ID_NONE ], - }, - priority: 100, - }; - if ( rule0.condition.requestDomains ) { - rule1.condition.initiatorDomains = - rule0.condition.requestDomains.slice(); - } else if ( rule0.condition.excludedRequestDomains ) { - rule1.condition.excludedInitiatorDomains = - rule0.condition.excludedRequestDomains.slice(); - } - addSessionRules.push(rule1); + requestDomains.push(...noneHostnames); } - - const noneCount = noneHostnames.has('all-urls') - ? -notNoneHostnames.size + const noneCount = allowEverywhere + ? notNoneHostnames.size : noneHostnames.size; - - const promises = []; - if ( isDifferentAllowRules(addDynamicRules, dynamicRules) ) { - promises.push(dnr.updateDynamicRules({ - addRules: addDynamicRules, - removeRuleIds: removeDynamicRuleIds, - })); - ubolLog(`Add "allowAllRequests" dynamic rule for ${noneCount} sites`); - } - if ( isDifferentAllowRules(addSessionRules, sessionRules) ) { - promises.push(dnr.updateSessionRules({ - addRules: addSessionRules, - removeRuleIds: removeSessionRuleIds, - })); - ubolLog(`Add "allow" session rule for ${noneCount} sites`); - } - if ( promises.length === 0 ) { return; } - return Promise.all(promises); -} - -const isDifferentAllowRules = (a, b) => { - const pp = [ - 'requestDomains', - 'excludedRequestDomains', - 'initiatorDomains', - 'excludedInitiatorDomains', - ]; - for ( const p of pp ) { - const ac = a?.length && a[0].condition[p] || []; - const bc = b?.length && b[0].condition[p] || []; - if ( ac.join() !== bc.join() ) { return true; } - } - return false; -}; + return dnr.setAllowAllRules( + TRUSTED_DIRECTIVE_BASE_RULE_ID, + requestDomains.sort(), + excludedRequestDomains.sort(), + allowEverywhere, + TRUSTED_DIRECTIVE_PRIORITY + ).then(modified => { + if ( modified === false ) { return; } + ubolLog(`${allowEverywhere ? 'Enabled' : 'Disabled'} DNR filtering for ${noneCount} sites`); + }); +} /******************************************************************************/ -async function defaultRulesetsFromLanguage() { +export async function getDefaultRulesetsFromEnv() { const dropCountry = lang => { const pos = lang.indexOf('-'); if ( pos === -1 ) { return lang; } @@ -594,21 +427,32 @@ `\\b(${Array.from(langSet).join('|')})\\b` ); - const manifest = runtime.getManifest(); - const rulesets = manifest.declarative_net_request.rule_resources; + const reMobile = /\bMobile\b/.test(navigator.userAgent) + ? /\bmobile\b/ + : null + const rulesetDetails = await getRulesetDetails(); const out = []; - for ( const ruleset of rulesets ) { + for ( const ruleset of rulesetDetails.values() ) { const { id, enabled } = ruleset; if ( enabled ) { out.push(id); continue; } - const details = rulesetDetails.get(id); - if ( typeof details.lang !== 'string' ) { continue; } - if ( reTargetLang.test(details.lang) === false ) { continue; } - out.push(id); + if ( typeof ruleset.lang === 'string' ) { + if ( reTargetLang.test(ruleset.lang) ) { + out.push(id); + continue; + } + } + if ( typeof ruleset.tags === 'string' ) { + if ( reMobile?.test(ruleset.tags) ) { + out.push(id); + continue; + } + } } + return out; } @@ -618,15 +462,12 @@ const [ oldDefaultIds = [], newDefaultIds, + staticRulesetIds, ] = await Promise.all([ localRead('defaultRulesetIds'), - defaultRulesetsFromLanguage(), + getDefaultRulesetsFromEnv(), + getStaticRulesets().then(r => r.map(a => a.id)), ]); - - const manifest = runtime.getManifest(); - const validIds = new Set( - manifest.declarative_net_request.rule_resources.map(r => r.id) - ); const toAdd = []; const toRemove = []; for ( const id of newDefaultIds ) { @@ -638,7 +479,7 @@ toRemove.push(id); } for ( const id of rulesetConfig.enabledRulesets ) { - if ( validIds.has(id) ) { continue; } + if ( staticRulesetIds.includes(id) ) { continue; } toRemove.push(id); } localWrite('defaultRulesetIds', newDefaultIds); @@ -655,7 +496,11 @@ async function enableRulesets(ids) { const afterIds = new Set(ids); - const [ beforeIds, adminIds, rulesetDetails ] = await Promise.all([ + const [ + beforeIds, + adminIds, + rulesetDetails, + ] = await Promise.all([ dnr.getEnabledRulesets().then(ids => new Set(ids)), getAdminRulesets(), getRulesetDetails(), @@ -693,9 +538,7 @@ disableRulesetSet.delete(id); } - if ( enableRulesetSet.size === 0 && disableRulesetSet.size === 0 ) { - return false; - } + if ( enableRulesetSet.size === 0 && disableRulesetSet.size === 0 ) { return; } const enableRulesetIds = Array.from(enableRulesetSet); const disableRulesetIds = Array.from(disableRulesetSet); @@ -706,11 +549,41 @@ if ( disableRulesetIds.length !== 0 ) { ubolLog(`Disable ruleset: ${disableRulesetIds}`); } - await dnr.updateEnabledRulesets({ enableRulesetIds, disableRulesetIds }); - await updateDynamicRules(); + const response = {}; + + await dnr.updateEnabledRulesets({ + enableRulesetIds, + disableRulesetIds, + }).catch(reason => { + ubolErr(`updateEnabledRulesets/${reason}`); + response.error = `${reason}`; + }); + + const result = await updateDynamicRules(); + if ( result?.error ) { + response.error ||= result.error; + } + + await dnr.getEnabledRulesets().then(enabledRulesets => { + ubolLog(`Enabled rulesets: ${enabledRulesets}`); + response.enabledRulesets = enabledRulesets; + return dnr.getAvailableStaticRuleCount(); + }).then(count => { + ubolLog(`Available static rule count: ${count}`); + response.staticRuleCount = count; + }).catch(reason => { + ubolErr(`getEnabledRulesets/${reason}`); + }); + + return response; +} + +/******************************************************************************/ - return true; +async function getStaticRulesets() { + const manifest = runtime.getManifest(); + return manifest.declarative_net_request.rule_resources; } /******************************************************************************/ @@ -734,15 +607,96 @@ /******************************************************************************/ +async function getEffectiveUserRules() { + const allRules = await dnr.getDynamicRules(); + const userRules = []; + for ( const rule of allRules ) { + if ( rule.id < USER_RULES_BASE_RULE_ID ) { continue; } + userRules.push(rule); + } + return userRules; +} + +async function updateUserRules() { + const [ + userRules, + userRulesText = '', + ] = await Promise.all([ + getEffectiveUserRules(), + localRead('userDnrRules'), + ]); + + const effectiveRulesText = rulesetConfig.developerMode + ? userRulesText + : ''; + + const parsed = rulesFromText(effectiveRulesText); + const { rules } = parsed; + const removeRuleIds = [ ...userRules.map(a => a.id) ]; + const rejectedRegexes = []; + const addRules = await pruneInvalidRegexRules('user', rules, rejectedRegexes); + const out = { added: 0, removed: 0, errors: [] }; + + if ( rejectedRegexes.length !== 0 ) { + rejectedRegexes.forEach(e => + out.errors.push(`regexFilter: ${e.regex} → ${e.reason}`) + ); + } + + if ( removeRuleIds.length === 0 && addRules.length === 0 ) { + await localRemove('userDnrRuleCount'); + return out; + } + + let ruleId = 0; + for ( const rule of addRules ) { + rule.id = USER_RULES_BASE_RULE_ID + ruleId++; + rule.priority = (rule.priority || 1) + USER_RULES_PRIORITY; + } + + // Rules are first removed separately to ensure registered rules match + // user rules text. A bad rule in user rules text would prevent the + // rules from being removed if the removal was done at the same time as + // adding rules. + try { + await dnr.updateDynamicRules({ removeRuleIds }); + await dnr.updateDynamicRules({ addRules }); + if ( removeRuleIds.length !== 0 ) { + ubolLog(`updateUserRules() / Removed ${removeRuleIds.length} dynamic DNR rules`); + } + if ( addRules.length !== 0 ) { + ubolLog(`updateUserRules() / Added ${addRules.length} DNR rules`); + } + out.added = addRules.length; + out.removed = removeRuleIds.length; + } catch(reason) { + ubolErr(`updateUserRules/${reason}`); + out.errors.push(`${reason}`); + } finally { + const userRules = await getEffectiveUserRules(); + if ( userRules.length === 0 ) { + await localRemove('userDnrRuleCount'); + } else { + await localWrite('userDnrRuleCount', addRules.length); + } + } + return out; +} + +/******************************************************************************/ + export { - defaultRulesetsFromLanguage, enableRulesets, excludeFromStrictBlock, filteringModesToDNR, - getRulesetDetails, + getEffectiveDynamicRules, + getEffectiveSessionRules, + getEffectiveUserRules, getEnabledRulesetsDetails, + getRulesetDetails, patchDefaultRulesets, setStrictBlockMode, updateDynamicRules, updateSessionRules, + updateUserRules, }; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/rw-dnr-editor.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/rw-dnr-editor.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/rw-dnr-editor.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/rw-dnr-editor.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,409 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2014-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { + browser, + localRead, + localRemove, + localWrite, + sendMessage, +} from './ext.js'; +import { dom, qs$ } from './dom.js'; +import { i18n, i18n$ } from './i18n.js'; +import { DNREditor } from './dnr-editor.js'; +import { parseFilters } from './ubo-parser.js'; +import { textFromRules } from './dnr-parser.js'; + +/******************************************************************************/ + +export class ReadWriteDNREditor extends DNREditor { + constructor(editor) { + super(); + this.feedbackPanel = self.cm6.createViewPanel(); + editor.panels.push(this.feedbackPanel); + } + + async getText() { + return localRead('userDnrRules'); + } + + on(editor) { + localRead('userDnrRuleCount').then(userDnrRuleCount => { + this.updateSummaryPanel(editor, { userDnrRuleCount }) + }); + browser.storage.onChanged.addListener((changes, area) => { + if ( area !== 'local' ) { return; } + const { userDnrRuleCount } = changes; + if ( userDnrRuleCount instanceof Object === false ) { return; } + const { newValue } = changes.userDnrRuleCount; + this.updateSummaryPanel(editor, { userDnrRuleCount: newValue }); + }); + } + + off(editor) { + this.updateSummaryPanel(editor, null); + this.updateFeedbackPanel(editor, null); + } + + rulesFromJSON(json) { + let content = json.trim(); + if ( /^[[{]/.test(content) === false ) { + const match = /^[^[{]+/.exec(content); + if ( match === null ) { return; } + content = content.slice(match[0].length); + } + const firstChar = content.charAt(0); + const expectedLastChar = firstChar === '[' ? ']' : '}'; + if ( content.at(-1) !== expectedLastChar ) { + const re = new RegExp(`\\${expectedLastChar}[^\\${expectedLastChar}]+$`); + const match = re.exec(content); + if ( match === null ) { return; } + content = content.slice(0, match.index+1); + } + if ( content.startsWith('{') && content.endsWith('}') ) { + content = `[${content}]`; + } + try { + const rules = JSON.parse(content); + if ( Array.isArray(rules) ) { return rules; } + } + catch { + } + } + + getAutocompleteCandidates(editor, from) { + const { scope } = editor.getScopeAt(from); + switch ( scope ) { + case '': + return { + before: /^$/, + candidates: [ + { token: 'action:', after: '\n' }, + { token: 'condition:', after: '\n ' }, + { token: 'priority:', after: ' ' }, + { token: '---', after: '\n' }, + ] + }; + case 'action:': + return { + before: /^ {2}$/, + candidates: [ + { token: 'type:', after: ' ' }, + { token: 'redirect:', after: '\n ' }, + { token: 'requestHeaders:', after: '\n - header: ' }, + { token: 'responseHeaders:', after: '\n - header: ' }, + ], + }; + case 'action:type:': + return { + before: /: $/, + candidates: [ + { token: 'block', after: '\n ' }, + { token: 'redirect', after: '\n ' }, + { token: 'allow', after: '\n ' }, + { token: 'modifyHeaders', after: '\n ' }, + { token: 'upgradeScheme', after: '\n ' }, + { token: 'allowAllRequest', after: '\n ' }, + ], + }; + case 'action:redirect:': + return { + before: /^ {4}$/, + candidates: [ + { token: 'extensionPath:', after: ' ' }, + { token: 'regexSubstitution:', after: ' ' }, + { token: 'transform:', after: '\n ' }, + { token: 'url:', after: ' ' }, + ], + }; + case 'action:redirect:transform:': + return { + before: /^ {6}$/, + candidates: [ + { token: 'fragment:', after: ' ' }, + { token: 'host:', after: ' ' }, + { token: 'path:', after: ' ' }, + { token: 'port:', after: ' ' }, + { token: 'query:', after: ' ' }, + { token: 'scheme:', after: ' ' }, + { token: 'queryTransform:', after: '\n ' }, + ], + }; + case 'action:redirect:transform:queryTransform:': + return { + before: /^ {8}$/, + candidates: [ + { token: 'addOrReplaceParams:', after: '\n - ' }, + { token: 'removeParams:', after: '\n - ' }, + ], + }; + case 'action:responseHeaders:': + case 'action:requestHeaders:': + return { + before: /^ {4}- $/, + candidates: [ + { token: 'header:', after: ' ' }, + ], + }; + case 'action:responseHeaders:header:': + case 'action:requestHeaders:header:': + return { + before: /^ {6}$/, + candidates: [ + { token: 'operation:', after: ' ' }, + { token: 'value:', after: ' ' }, + ], + }; + case 'action:responseHeaders:header:operation:': + case 'action:requestHeaders:header:operation:': + return { + before: /: $/, + candidates: [ + { token: 'append', after: '\n value: ' }, + { token: 'set', after: '\n value: ' }, + { token: 'remove', after: '\n ' }, + ], + }; + case 'condition:': + return { + before: /^ {2}$/, + candidates: [ + { token: 'domainType:', after: ' ' }, + { token: 'isUrlFilterCaseSensitive:', after: ' ' }, + { token: 'regexFilter:', after: ' ' }, + { token: 'urlFilter:', after: ' ' }, + { token: 'initiatorDomains:', after: '\n - ' }, + { token: 'excludedInitiatorDomains:', after: '\n - ' }, + { token: 'requestDomains:', after: '\n - ' }, + { token: 'excludedRequestDomains:', after: '\n - ' }, + { token: 'resourceTypes:', after: '\n - ' }, + { token: 'excludedResourceTypes:', after: '\n - ' }, + { token: 'requestMethods:', after: '\n - ' }, + { token: 'excludedRequestMethods:', after: '\n - ' }, + { token: 'responseHeaders:', after: '\n - ' }, + { token: 'excludedResponseHeaders:', after: '\n - ' }, + ], + }; + case 'condition:domainType:': + return { + before: /: $/, + candidates: [ + { token: 'firstParty', after: '\n ' }, + { token: 'thirdParty', after: '\n ' }, + ], + }; + case 'condition:isUrlFilterCaseSensitive:': + return { + before: /: $/, + candidates: [ + { token: 'true', after: '\n ' }, + { token: 'false', after: '\n ' }, + ], + }; + case 'condition:requestMethods:': + case 'condition:excludedRequestMethods:': + return { + before: /^ {4}- $/, + candidates: [ + { token: 'connect', after: '\n - ' }, + { token: 'delete', after: '\n - ' }, + { token: 'get', after: '\n - ' }, + { token: 'head', after: '\n - ' }, + { token: 'options', after: '\n - ' }, + { token: 'patch', after: '\n - ' }, + { token: 'post', after: '\n - ' }, + { token: 'put', after: '\n - ' }, + { token: 'other', after: '\n ' }, + ], + }; + case 'condition:resourceTypes:': + case 'condition:excludedResourceTypes:': + return { + before: /^ {4}- $/, + candidates: [ + { token: 'main_frame', after: '\n - ' }, + { token: 'sub_frame', after: '\n - ' }, + { token: 'stylesheet', after: '\n - ' }, + { token: 'script', after: '\n - ' }, + { token: 'image', after: '\n - ' }, + { token: 'font', after: '\n - ' }, + { token: 'object', after: '\n - ' }, + { token: 'xmlhttprequest', after: '\n - ' }, + { token: 'ping', after: '\n - ' }, + { token: 'csp_report', after: '\n - ' }, + { token: 'media', after: '\n - ' }, + { token: 'websocket', after: '\n - ' }, + { token: 'webtransport', after: '\n - ' }, + { token: 'webbundle', after: '\n - ' }, + { token: 'other', after: '\n ' }, + ], + }; + } + } + + autoComplete(editor, context) { + const match = context.matchBefore(/[\w-]*/); + if ( match === undefined ) { return null; } + const result = this.getAutocompleteCandidates(editor, match.from); + if ( result === undefined ) { return null; } + if ( result.before !== undefined ) { + const { doc } = context.state; + const line = doc.lineAt(context.pos); + const before = doc.sliceString(line.from, match.from); + if ( result.before.test(before) === false ) { return null; } + } + const filtered = result.candidates.filter(e => + e.token !== match.text || e.after !== '\n' + ); + return { + from: match.from, + options: filtered.map(e => ({ label: e.token, apply: `${e.token}${e.after}` })), + validFor: /\w*/, + }; + } + + async saveEditorText(editor) { + const text = editor.getEditorText().trim(); + await (text.length !== 0 + ? localWrite('userDnrRules', text) + : localRemove('userDnrRules') + ); + const response = await sendMessage({ what: 'updateUserDnrRules' }) + if ( response instanceof Object ) { + this.updateFeedbackPanel(editor, response); + } + return true; + } + + updateSummaryPanel(editor, details) { + if ( details instanceof Object === false ) { + return editor.updateSummaryPanel(null); + } + const template = document.querySelector('template.summary-panel'); + const fragment = template.content.cloneNode(true); + const root = fragment.querySelector('.summary-panel'); + i18n.render(root); + const info = root.querySelector('.info'); + info.textContent = i18n$('dnrRulesCountInfo') + .replace('{count}', (details.userDnrRuleCount || 0).toLocaleString()) + editor.updateSummaryPanel(root); + } + + updateFeedbackPanel(editor, details) { + if ( details instanceof Object === false ) { + return this.feedbackPanel.render(editor.view, null); + } + const errors = []; + if ( Array.isArray(details.errors) ) { + details.errors.forEach(e => errors.push(e)); + } + const text = errors.join('\n'); + const config = (( ) => { + if ( text === '' ) { return null; } + const template = document.querySelector('template.feedback-panel'); + const fragment = template.content.cloneNode(true); + const root = fragment.querySelector('.feedback-panel'); + const info = root.querySelector('.info'); + info.textContent = text; + const closeFn = this.updateFeedbackPanel.bind(this, editor, null); + return { + dom: root, + mount() { + dom.on(qs$('.feedback-panel .close'), 'click', closeFn); + } + }; + })(); + this.feedbackPanel.render(editor.view, config); + } + + importFromFile(editor, json) { + const rules = this.rulesFromJSON(json); + if ( rules === undefined ) { return; } + const text = textFromRules(rules); + if ( text === undefined ) { return; } + const { doc } = editor.view.state; + const lastChars = doc.toString().trimEnd().slice(-4); + const lastLine = doc.line(doc.lines); + let from = lastLine.to; + let prepend = ''; + if ( lastLine.text !== '' ) { + prepend = '\n'; + } else { + from = lastLine.from; + } + if ( /(?:^|\n)---$/.test(lastChars) === false ) { + prepend = `${prepend}---\n`; + } + editor.view.dispatch({ changes: { from, insert: `${prepend}${text}` } }); + self.cm6.foldAll(editor.view); + editor.view.focus(); + } + + exportToFile(text) { + return super.exportToFile(text, 'my-ubol-dnr-rules.json'); + } + + importFromPaste(editor, transaction) { + const { from, to } = editor.rangeFromTransaction(transaction); + if ( from === undefined || to === undefined ) { return; } + // Paste position must match start of a line + const { newDoc } = transaction; + const lineFrom = newDoc.lineAt(from); + if ( lineFrom.from !== from ) { return; } + // Paste position must match a rule boundary + let separatorBefore = false; + if ( lineFrom.number !== 1 ) { + const lineBefore = newDoc.line(lineFrom.number-1); + if ( /^---\s*$/.test(lineBefore.text) === false ) { return; } + separatorBefore = true; + } + const pastedText = newDoc.sliceString(from, to); + let linesToPrepend; + let rules = this.rulesFromJSON(pastedText); + if ( Boolean(rules?.length) === false ) { + rules = parseFilters(pastedText); + if ( Boolean(rules?.length) === false ) { return; } + const lines = pastedText.trim().split(/\n/); + linesToPrepend = lines.slice(0, 10).map(a => `# ${a}`); + if ( lines.length > linesToPrepend.length ) { + linesToPrepend.push('# ...'); + } + } + let yamlText = textFromRules(rules); + if ( yamlText === undefined ) { return; } + if ( linesToPrepend ) { + yamlText = yamlText.replace('---\n', `---\n${linesToPrepend.join('\n')}\n`); + } + if ( separatorBefore && yamlText.startsWith('---\n') ) { + yamlText = yamlText.slice(4); + } + editor.view.dispatch({ changes: { from, to, insert: yamlText } }); + self.cm6.foldAll(editor.view); + return true; + } + + newlineAssistant = { + 'action:': ' type: ', + 'action:responseHeaders:header:': ' operation: ', + }; + + ioAccept = '.json,application/json'; +}; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/css-api.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-api.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/css-api.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-api.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,33 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +(api => { + if ( typeof api === 'object' ) { return; } + self.cssAPI = { + insert(css) { + chrome.runtime.sendMessage({ + what: 'insertCSS', + css, + }).catch(( ) => { + }); + }, + }; +})(self.cssAPI); diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/css-declarative.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-declarative.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/css-declarative.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-declarative.js 1970-01-01 00:00:00.000000000 +0000 @@ -1,157 +0,0 @@ -/******************************************************************************* - - uBlock Origin Lite - a comprehensive, MV3-compliant content blocker - Copyright (C) 2014-present Raymond Hill - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see {http://www.gnu.org/licenses/}. - - Home: https://github.com/gorhill/uBlock -*/ - -/* jshint esversion:11 */ - -'use strict'; - -/******************************************************************************/ - -// Important! -// Isolate from global scope -(function uBOL_cssDeclarative() { - -/******************************************************************************/ - -const declarativeImports = self.declarativeImports || []; -self.declarativeImports = undefined; -delete self.declarativeImports; - -/******************************************************************************/ - -const hnParts = []; -try { hnParts.push(...document.location.hostname.split('.')); } -catch(ex) { } -const hnpartslen = hnParts.length; -if ( hnpartslen === 0 ) { return; } - -const selectors = []; - -for ( const { argsList, exceptionsMap, hostnamesMap, entitiesMap } of declarativeImports ) { - const todoIndices = new Set(); - const tonotdoIndices = []; - // Exceptions - if ( exceptionsMap.size !== 0 ) { - for ( let i = 0; i < hnpartslen; i++ ) { - const hn = hnParts.slice(i).join('.'); - const excepted = exceptionsMap.get(hn); - if ( excepted ) { tonotdoIndices.push(...excepted); } - } - exceptionsMap.clear(); - } - // Hostname-based - if ( hostnamesMap.size !== 0 ) { - const collectArgIndices = hn => { - let argsIndices = hostnamesMap.get(hn); - if ( argsIndices === undefined ) { return; } - if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; } - for ( const argsIndex of argsIndices ) { - if ( tonotdoIndices.includes(argsIndex) ) { continue; } - todoIndices.add(argsIndex); - } - }; - for ( let i = 0; i < hnpartslen; i++ ) { - const hn = hnParts.slice(i).join('.'); - collectArgIndices(hn); - } - collectArgIndices('*'); - hostnamesMap.clear(); - } - // Entity-based - if ( entitiesMap.size !== 0 ) { - const n = hnpartslen - 1; - for ( let i = 0; i < n; i++ ) { - for ( let j = n; j > i; j-- ) { - const en = hnParts.slice(i,j).join('.'); - let argsIndices = entitiesMap.get(en); - if ( argsIndices === undefined ) { continue; } - if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; } - for ( const argsIndex of argsIndices ) { - if ( tonotdoIndices.includes(argsIndex) ) { continue; } - todoIndices.add(argsIndex); - } - } - } - entitiesMap.clear(); - } - for ( const i of todoIndices ) { - selectors.push(...argsList[i].map(json => JSON.parse(json))); - } - argsList.length = 0; -} -declarativeImports.length = 0; - -if ( selectors.length === 0 ) { return; } - -/******************************************************************************/ - -const cssRuleFromProcedural = details => { - const { tasks, action } = details; - let mq, selector; - if ( Array.isArray(tasks) ) { - if ( tasks[0][0] !== 'matches-media' ) { return; } - mq = tasks[0][1]; - if ( tasks.length > 2 ) { return; } - if ( tasks.length === 2 ) { - if ( tasks[1][0] !== 'spath' ) { return; } - selector = tasks[1][1]; - } - } - let style; - if ( Array.isArray(action) ) { - if ( action[0] !== 'style' ) { return; } - selector = selector || details.selector; - style = action[1]; - } - if ( mq === undefined && style === undefined && selector === undefined ) { return; } - if ( mq === undefined ) { - return `${selector}\n{${style}}`; - } - if ( style === undefined ) { - return `@media ${mq} {\n${selector}\n{display:none!important;}\n}`; - } - return `@media ${mq} {\n${selector}\n{${style}}\n}`; -}; - -const sheetText = []; -for ( const selector of selectors ) { - const ruleText = cssRuleFromProcedural(selector); - if ( ruleText === undefined ) { continue; } - sheetText.push(ruleText); -} - -if ( sheetText.length === 0 ) { return; } - -(function uBOL_injectCSS(css, count = 10) { - chrome.runtime.sendMessage({ what: 'insertCSS', css }).catch(( ) => { - count -= 1; - if ( count === 0 ) { return; } - uBOL_injectCSS(css, count - 1); - }); -})(sheetText.join('\n')); - -/******************************************************************************/ - -})(); - -/******************************************************************************/ - -void 0; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/css-generic.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-generic.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/css-generic.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-generic.js 2025-10-25 19:32:51.000000000 +0000 @@ -26,10 +26,15 @@ (function uBOL_cssGeneric() { const genericSelectorMap = self.genericSelectorMap || new Map(); -delete self.genericSelectorMap; - +self.genericSelectorMap = undefined; if ( genericSelectorMap.size === 0 ) { return; } +const genericExceptionSieve = self.genericExceptionSieve || new Set(); +self.genericExceptionSieve = undefined; + +const genericExceptionMap = self.genericExceptionMap || new Map(); +self.genericExceptionMap = undefined; + /******************************************************************************/ const maxSurveyTimeSlice = 4; @@ -56,7 +61,7 @@ for ( let i = 0; i < len; i += step ) { hash = (hash << 5) + hash ^ s.charCodeAt(i); } - return hash & 0xFFFFFF; + return hash & 0xFFF; }; /******************************************************************************/ @@ -76,7 +81,11 @@ const selectorList = genericSelectorMap.get(hash); if ( selectorList === undefined ) { return; } genericSelectorMap.delete(hash); - out.push(selectorList); + if ( genericExceptionSieve.has(hash) ) { + applyExceptions(selectorList, out); + } else { + out.push(selectorList); + } }; // https://github.com/uBlockOrigin/uBlock-issues/discussions/2076 @@ -96,10 +105,28 @@ const selectorList = genericSelectorMap.get(hash); if ( selectorList === undefined ) { continue; } genericSelectorMap.delete(hash); - out.push(selectorList); + if ( genericExceptionSieve.has(hash) ) { + applyExceptions(selectorList, out); + } else { + out.push(selectorList); + } } }; +const applyExceptions = (selectorList, out) => { + const selectors = new Set(selectorList.split(',\n')); + self.isolatedAPI.forEachHostname(hostname => { + const exceptions = genericExceptionMap.get(hostname); + if ( exceptions === undefined ) { return; } + for ( const exception of exceptions.split('\n') ) { + selectors.delete(exception); + } + if ( selectors.size === 0 ) { return true; } + }, { hasEntities: true }); + if ( selectors.size === 0 ) { return; } + out.push(Array.from(selectors).join(',\n')); +} + /******************************************************************************/ const pendingNodes = { @@ -161,7 +188,7 @@ if ( styleSheetTimer !== undefined ) { return; } styleSheetTimer = self.requestAnimationFrame(( ) => { styleSheetTimer = undefined; - uBOL_injectCSS(`${styleSheetSelectors.join(',')}{display:none!important;}`); + self.cssAPI.insert(`${styleSheetSelectors.join(',')}{display:none!important;}`); styleSheetSelectors.length = 0; }); }; @@ -187,12 +214,15 @@ /******************************************************************************/ -const uBOL_injectCSS = (css, count = 10) => { - chrome.runtime.sendMessage({ what: 'insertCSS', css }).catch(( ) => { - count -= 1; - if ( count === 0 ) { return; } - uBOL_injectCSS(css, count - 1); - }); +const stopAll = ( ) => { + if ( domChangeTimer !== undefined ) { + self.clearTimeout(domChangeTimer); + domChangeTimer = undefined; + } + domMutationObserver.disconnect(); + domMutationObserver.takeRecords(); + domMutationObserver = undefined; + genericSelectorMap.clear(); }; /******************************************************************************/ @@ -219,20 +249,6 @@ /******************************************************************************/ -const stopAll = reason => { - if ( domChangeTimer !== undefined ) { - self.clearTimeout(domChangeTimer); - domChangeTimer = undefined; - } - domMutationObserver.disconnect(); - domMutationObserver.takeRecords(); - domMutationObserver = undefined; - genericSelectorMap.clear(); - console.info(`uBOL: Generic cosmetic filtering stopped because ${reason}`); -}; - -/******************************************************************************/ - })(); /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/css-procedural-api.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-procedural-api.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/css-procedural-api.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-procedural-api.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,813 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2014-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +// Important! +// Isolate from global scope +(function uBOL_cssProceduralAPI() { + +if ( self.ProceduralFiltererAPI !== undefined ) { + if ( self.ProceduralFiltererAPI instanceof Promise === false ) { return; } +} + +/******************************************************************************/ + +const nonVisualElements = { + head: true, + link: true, + meta: true, + script: true, + style: true, +}; + +const regexFromString = (s, exact = false) => { + if ( s === '' ) { return /^/; } + const match = /^\/(.+)\/([imu]*)$/.exec(s); + if ( match !== null ) { + return new RegExp(match[1], match[2] || undefined); + } + const reStr = s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + return new RegExp(exact ? `^${reStr}$` : reStr); +}; + +const randomToken = ( ) => { + const n = Math.random(); + return String.fromCharCode(n * 25 + 97) + + Math.floor( + (0.25 + n * 0.75) * Number.MAX_SAFE_INTEGER + ).toString(36).slice(-8); +}; + +/******************************************************************************/ + +// 'P' stands for 'Procedural' + +class PSelectorTask { + destructor() { + } + begin() { + } + end() { + } +} + +/******************************************************************************/ + +class PSelectorVoidTask extends PSelectorTask { + constructor(filterer, task) { + super(); + console.info(`uBO: :${task[0]}() operator does not exist`); + } + transpose() { + } +} + +/******************************************************************************/ + +class PSelectorHasTextTask extends PSelectorTask { + constructor(filterer, task) { + super(); + this.needle = regexFromString(task[1]); + } + transpose(node, output) { + if ( this.needle.test(node.textContent) ) { + output.push(node); + } + } +} + +/******************************************************************************/ + +class PSelectorIfTask extends PSelectorTask { + constructor(filterer, task) { + super(); + this.pselector = new PSelector(filterer, task[1]); + } + transpose(node, output) { + if ( this.pselector.test(node) === this.target ) { + output.push(node); + } + } + target = true; +} + +class PSelectorIfNotTask extends PSelectorIfTask { + target = false; +} + +/******************************************************************************/ + +class PSelectorMatchesAttrTask extends PSelectorTask { + constructor(filterer, task) { + super(); + this.reAttr = regexFromString(task[1].attr, true); + this.reValue = regexFromString(task[1].value, true); + } + transpose(node, output) { + if ( typeof node.getAttributeNames !== 'function' ) { return; } + const attrs = node.getAttributeNames(); + for ( const attr of attrs ) { + if ( this.reAttr.test(attr) === false ) { continue; } + if ( this.reValue.test(node.getAttribute(attr)) === false ) { continue; } + output.push(node); + } + } +} + +/******************************************************************************/ + +class PSelectorMatchesCSSTask extends PSelectorTask { + constructor(filterer, task) { + super(); + this.name = task[1].name; + this.pseudo = task[1].pseudo ? `::${task[1].pseudo}` : null; + let arg0 = task[1].value, arg1; + if ( Array.isArray(arg0) ) { + arg1 = arg0[1]; arg0 = arg0[0]; + } + this.value = new RegExp(arg0, arg1); + } + transpose(node, output) { + const style = window.getComputedStyle(node, this.pseudo); + if ( style !== null && this.value.test(style[this.name]) ) { + output.push(node); + } + } +} +class PSelectorMatchesCSSAfterTask extends PSelectorMatchesCSSTask { + constructor(filterer, task) { + super(filterer, task); + this.pseudo = '::after'; + } +} + +class PSelectorMatchesCSSBeforeTask extends PSelectorMatchesCSSTask { + constructor(filterer, task) { + super(filterer, task); + this.pseudo = '::before'; + } +} + +/******************************************************************************/ + +class PSelectorMatchesMediaTask extends PSelectorTask { + constructor(filterer, task) { + super(); + this.filterer = filterer; + this.mql = window.matchMedia(task[1]); + if ( this.mql.media === 'not all' ) { return; } + this.boundHandler = this.handler.bind(this); + this.mql.addEventListener('change', this.boundHandler); + } + destructor() { + super.destructor(); + this.mql.removeEventListener('change', this.boundHandler); + } + transpose(node, output) { + if ( this.mql.matches === false ) { return; } + output.push(node); + } + handler() { + if ( this.filterer instanceof Object === false ) { return; } + this.filterer.uBOL_DOMChanged(); + } +} + +/******************************************************************************/ + +class PSelectorMatchesPathTask extends PSelectorTask { + constructor(filterer, task) { + super(); + this.needle = regexFromString( + task[1].replace(/\P{ASCII}/gu, s => encodeURIComponent(s)) + ); + } + transpose(node, output) { + if ( this.needle.test(self.location.pathname + self.location.search) ) { + output.push(node); + } + } +} + +/******************************************************************************/ + +class PSelectorMatchesPropTask extends PSelectorTask { + constructor(filterer, task) { + super(); + this.props = task[1].attr.split('.'); + this.reValue = task[1].value !== '' + ? regexFromString(task[1].value, true) + : null; + } + transpose(node, output) { + let value = node; + for ( const prop of this.props ) { + if ( value === undefined ) { return; } + if ( value === null ) { return; } + value = value[prop]; + } + if ( this.reValue === null ) { + if ( value === undefined ) { return; } + } else if ( this.reValue.test(value) === false ) { + return; + } + output.push(node); + } +} + +/******************************************************************************/ + +class PSelectorMinTextLengthTask extends PSelectorTask { + constructor(filterer, task) { + super(); + this.min = task[1]; + } + transpose(node, output) { + if ( node.textContent.length >= this.min ) { + output.push(node); + } + } +} + +/******************************************************************************/ + +class PSelectorOthersTask extends PSelectorTask { + constructor() { + super(); + this.targets = new Set(); + } + begin() { + this.targets.clear(); + } + end(output) { + const toKeep = new Set(this.targets); + const toDiscard = new Set(); + const body = document.body; + const head = document.head; + let discard = null; + for ( let keep of this.targets ) { + while ( keep !== null && keep !== body && keep !== head ) { + toKeep.add(keep); + toDiscard.delete(keep); + discard = keep.previousElementSibling; + while ( discard !== null ) { + if ( nonVisualElements[discard.localName] !== true ) { + if ( toKeep.has(discard) === false ) { + toDiscard.add(discard); + } + } + discard = discard.previousElementSibling; + } + discard = keep.nextElementSibling; + while ( discard !== null ) { + if ( nonVisualElements[discard.localName] !== true ) { + if ( toKeep.has(discard) === false ) { + toDiscard.add(discard); + } + } + discard = discard.nextElementSibling; + } + keep = keep.parentElement; + } + } + for ( discard of toDiscard ) { + output.push(discard); + } + this.targets.clear(); + } + transpose(candidate) { + for ( const target of this.targets ) { + if ( target.contains(candidate) ) { return; } + if ( candidate.contains(target) ) { + this.targets.delete(target); + } + } + this.targets.add(candidate); + } +} + +/******************************************************************************/ + +class PSelectorShadowTask extends PSelectorTask { + constructor(filterer, task) { + super(); + this.selector = task[1]; + } + transpose(node, output) { + const root = this.openOrClosedShadowRoot(node); + if ( root === null ) { return; } + const nodes = root.querySelectorAll(this.selector); + output.push(...nodes); + } + get openOrClosedShadowRoot() { + if ( PSelectorShadowTask.openOrClosedShadowRoot !== undefined ) { + return PSelectorShadowTask.openOrClosedShadowRoot; + } + if ( typeof chrome === 'object' && chrome !== null ) { + if ( chrome.dom instanceof Object ) { + if ( typeof chrome.dom.openOrClosedShadowRoot === 'function' ) { + PSelectorShadowTask.openOrClosedShadowRoot = + chrome.dom.openOrClosedShadowRoot; + return PSelectorShadowTask.openOrClosedShadowRoot; + } + } + } + PSelectorShadowTask.openOrClosedShadowRoot = node => + node.openOrClosedShadowRoot || null; + return PSelectorShadowTask.openOrClosedShadowRoot; + } +} + +/******************************************************************************/ + +// https://github.com/AdguardTeam/ExtendedCss/issues/31#issuecomment-302391277 +// Prepend `:scope ` if needed. +class PSelectorSpathTask extends PSelectorTask { + constructor(filterer, task) { + super(); + this.spath = task[1]; + this.nth = /^(?:\s*[+~]|:)/.test(this.spath); + if ( this.nth ) { return; } + if ( /^\s*>/.test(this.spath) ) { + this.spath = `:scope ${this.spath.trim()}`; + } + } + transpose(node, output) { + const nodes = this.nth + ? PSelectorSpathTask.qsa(node, this.spath) + : node.querySelectorAll(this.spath); + for ( const node of nodes ) { + output.push(node); + } + } + // Helper method for other operators. + static qsa(node, selector) { + const parent = node.parentElement; + if ( parent === null ) { return []; } + let pos = 1; + for (;;) { + node = node.previousElementSibling; + if ( node === null ) { break; } + pos += 1; + } + return parent.querySelectorAll( + `:scope > :nth-child(${pos})${selector}` + ); + } +} + +/******************************************************************************/ + +class PSelectorUpwardTask extends PSelectorTask { + constructor(filterer, task) { + super(); + const arg = task[1]; + if ( typeof arg === 'number' ) { + this.i = arg; + } else { + this.s = arg; + } + } + transpose(node, output) { + if ( this.s !== '' ) { + const parent = node.parentElement; + if ( parent === null ) { return; } + node = parent.closest(this.s); + if ( node === null ) { return; } + } else { + let nth = this.i; + for (;;) { + node = node.parentElement; + if ( node === null ) { return; } + nth -= 1; + if ( nth === 0 ) { break; } + } + } + output.push(node); + } + i = 0; + s = ''; +} + +/******************************************************************************/ + +class PSelectorWatchAttrs extends PSelectorTask { + constructor(filterer, task) { + super(); + this.filterer = filterer; + this.observer = null; + this.observed = new WeakSet(); + this.observerOptions = { + attributes: true, + subtree: true, + }; + const attrs = task[1]; + if ( Array.isArray(attrs) && attrs.length !== 0 ) { + this.observerOptions.attributeFilter = task[1]; + } + } + destructor() { + super.destructor(); + if ( this.observer ) { + this.observer.takeRecords(); + this.observer.disconnect(); + this.observer = null; + } + } + transpose(node, output) { + output.push(node); + if ( this.filterer instanceof Object === false ) { return; } + if ( this.observed.has(node) ) { return; } + if ( this.observer === null ) { + this.observer = new MutationObserver(( ) => { + this.filterer.uBOL_DOMChanged(); + }); + } + this.observer.observe(node, this.observerOptions); + this.observed.add(node); + } +} + +/******************************************************************************/ + +class PSelectorXpathTask extends PSelectorTask { + constructor(filterer, task) { + super(); + this.xpe = document.createExpression(task[1], null); + this.xpr = null; + } + transpose(node, output) { + this.xpr = this.xpe.evaluate( + node, + XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, + this.xpr + ); + let j = this.xpr.snapshotLength; + while ( j-- ) { + const node = this.xpr.snapshotItem(j); + if ( node.nodeType === 1 ) { + output.push(node); + } + } + } +} + +/******************************************************************************/ + +class PSelector { + constructor(filterer, o) { + this.selector = o.selector; + this.tasks = []; + const tasks = []; + if ( Array.isArray(o.tasks) === false ) { return; } + for ( const task of o.tasks ) { + const ctor = PSelector.operatorToTaskMap.get(task[0]) || PSelectorVoidTask; + tasks.push(new ctor(filterer, task)); + } + this.tasks = tasks; + } + destructor() { + for ( const task of this.tasks ) { + task.destructor(); + } + } + prime(input) { + const root = input || document; + if ( this.selector === '' ) { return [ root ]; } + if ( input !== document ) { + const c0 = this.selector.charCodeAt(0); + if ( c0 === 0x2B /* + */ || c0 === 0x7E /* ~ */ ) { + return Array.from(PSelectorSpathTask.qsa(input, this.selector)); + } else if ( c0 === 0x3E /* > */ ) { + return Array.from(input.querySelectorAll(`:scope ${this.selector}`)); + } + } + return Array.from(root.querySelectorAll(this.selector)); + } + exec(input) { + let nodes = this.prime(input); + for ( const task of this.tasks ) { + if ( nodes.length === 0 ) { break; } + const transposed = []; + task.begin(); + for ( const node of nodes ) { + task.transpose(node, transposed); + } + task.end(transposed); + nodes = transposed; + } + return nodes; + } + test(input) { + const nodes = this.prime(input); + for ( const node of nodes ) { + let output = [ node ]; + for ( const task of this.tasks ) { + const transposed = []; + task.begin(); + for ( const node of output ) { + task.transpose(node, transposed); + } + task.end(transposed); + output = transposed; + if ( output.length === 0 ) { break; } + } + if ( output.length !== 0 ) { return true; } + } + return false; + } + static operatorToTaskMap = new Map([ + [ 'has', PSelectorIfTask ], + [ 'has-text', PSelectorHasTextTask ], + [ 'if', PSelectorIfTask ], + [ 'if-not', PSelectorIfNotTask ], + [ 'matches-attr', PSelectorMatchesAttrTask ], + [ 'matches-css', PSelectorMatchesCSSTask ], + [ 'matches-css-after', PSelectorMatchesCSSAfterTask ], + [ 'matches-css-before', PSelectorMatchesCSSBeforeTask ], + [ 'matches-media', PSelectorMatchesMediaTask ], + [ 'matches-path', PSelectorMatchesPathTask ], + [ 'matches-prop', PSelectorMatchesPropTask ], + [ 'min-text-length', PSelectorMinTextLengthTask ], + [ 'not', PSelectorIfNotTask ], + [ 'others', PSelectorOthersTask ], + [ 'shadow', PSelectorShadowTask ], + [ 'spath', PSelectorSpathTask ], + [ 'upward', PSelectorUpwardTask ], + [ 'watch-attr', PSelectorWatchAttrs ], + [ 'xpath', PSelectorXpathTask ], + ]); +} + +/******************************************************************************/ + +class PSelectorRoot extends PSelector { + constructor(filterer, o) { + super(filterer, o); + this.budget = 200; // I arbitrary picked a 1/5 second + this.raw = o.raw; + this.cost = 0; + this.lastAllowanceTime = 0; + this.action = o.action; + } + prime(input) { + try { + return super.prime(input); + } catch { + } + return []; + } + exec(input) { + try { + return super.exec(input); + } catch { + } + return []; + } +} + +/******************************************************************************/ + +class ProceduralFilterer { + constructor() { + this.selectors = []; + this.styleTokenMap = new Map(); + this.styledNodes = new Set(); + this.timer = undefined; + this.hideStyle = 'display:none!important;'; + } + + async reset() { + if ( this.timer ) { + self.cancelAnimationFrame(this.timer); + this.timer = undefined; + } + for ( const pselector of this.selectors.values() ) { + pselector.destructor(); + } + this.selectors.length = 0; + const promises = []; + for ( const [ style, token ] of this.styleTokenMap ) { + for ( const elem of this.styledNodes ) { + elem.removeAttribute(token); + } + const css = `[${token}]\n{${style}}\n`; + promises.push( + chrome.runtime.sendMessage({ what: 'removeCSS', css }).catch(( ) => { }) + ); + } + this.styleTokenMap.clear(); + this.styledNodes.clear(); + return Promise.all(promises); + } + + addSelectors(selectors) { + for ( const selector of selectors ) { + const pselector = new PSelectorRoot(this, selector); + this.primeProceduralSelector(pselector); + this.selectors.push(pselector); + } + } + + // This allows to perform potentially expensive initialization steps + // before the filters are ready to be applied. + primeProceduralSelector(pselector) { + if ( pselector.action === undefined ) { + this.styleTokenFromStyle(this.hideStyle); + } else if ( pselector.action[0] === 'style' ) { + this.styleTokenFromStyle(pselector.action[1]); + } + return pselector; + } + + uBOL_commit() { + if ( this.timer !== undefined ) { + self.cancelAnimationFrame(this.timer); + this.timer = undefined; + } + + // https://github.com/uBlockOrigin/uBlock-issues/issues/341 + // Be ready to unhide nodes which no longer matches any of + // the procedural selectors. + const toUnstyle = this.styledNodes; + this.styledNodes = new Set(); + + let t0 = Date.now(); + + for ( const pselector of this.selectors.values() ) { + const allowance = Math.floor((t0 - pselector.lastAllowanceTime) / 2000); + if ( allowance >= 1 ) { + pselector.budget += allowance * 50; + if ( pselector.budget > 200 ) { pselector.budget = 200; } + pselector.lastAllowanceTime = t0; + } + if ( pselector.budget <= 0 ) { continue; } + const nodes = pselector.exec(); + const t1 = Date.now(); + pselector.budget += t0 - t1; + if ( pselector.budget < -500 ) { + console.info('uBOL: disabling %s', pselector.raw); + pselector.budget = -0x7FFFFFFF; + } + t0 = t1; + if ( nodes.length === 0 ) { continue; } + this.processNodes(nodes, pselector.action); + } + + this.unprocessNodes(toUnstyle); + } + + styleTokenFromStyle(style) { + if ( style === undefined ) { return; } + let styleToken = this.styleTokenMap.get(style); + if ( styleToken !== undefined ) { return styleToken; } + styleToken = randomToken(); + this.styleTokenMap.set(style, styleToken); + self.cssAPI.insert(`[${styleToken}]\n{${style}}\n`); + return styleToken; + } + + processNodes(nodes, action) { + const op = action && action[0] || ''; + const arg = op !== '' ? action[1] : ''; + switch ( op ) { + case '': + /* fall through */ + case 'style': { + const styleToken = this.styleTokenFromStyle( + arg === '' ? this.hideStyle : arg + ); + for ( const node of nodes ) { + node.setAttribute(styleToken, ''); + this.styledNodes.add(node); + } + break; + } + case 'remove': { + for ( const node of nodes ) { + node.remove(); + node.textContent = ''; + } + break; + } + case 'remove-attr': { + const reAttr = regexFromString(arg, true); + for ( const node of nodes ) { + for ( const name of node.getAttributeNames() ) { + if ( reAttr.test(name) === false ) { continue; } + node.removeAttribute(name); + } + } + break; + } + case 'remove-class': { + const reClass = regexFromString(arg, true); + for ( const node of nodes ) { + const cl = node.classList; + for ( const name of cl.values() ) { + if ( reClass.test(name) === false ) { continue; } + cl.remove(name); + } + } + break; + } + default: + break; + } + } + + unprocessNodes(nodes) { + const tokens = Array.from(this.styleTokenMap.values()); + for ( const node of nodes ) { + if ( this.styledNodes.has(node) ) { continue; } + for ( const token of tokens ) { + node.removeAttribute(token); + } + } + } + + uBOL_DOMChanged() { + if ( this.timer !== undefined ) { return; } + this.timer = self.requestAnimationFrame(( ) => { + this.timer = undefined; + this.uBOL_commit(); + }); + } +} + +/******************************************************************************/ + +self.ProceduralFiltererAPI = class { + constructor() { + this.proceduralFilterer = null; + this.domObserver = null; + } + + async reset() { + if ( this.domObserver ) { + this.domObserver.takeRecords(); + this.domObserver.disconnect(); + this.domObserver = null; + } + if ( this.proceduralFilterer ) { + await this.proceduralFilterer.reset(); + this.proceduralFilterer = null; + } + } + + addSelectors(selectors) { + if ( this.proceduralFilterer === null ) { + this.proceduralFilterer = new ProceduralFilterer(); + } + if ( this.domObserver === null ) { + this.domObserver = new MutationObserver(mutations => { + this.onDOMChanged(mutations); + }); + this.domObserver.observe(document, { childList: true, subtree: true }); + } + this.proceduralFilterer.addSelectors(selectors); + this.proceduralFilterer.uBOL_commit(); + } + + qsa(selector) { + const o = JSON.parse(selector); + const pselector = new PSelectorRoot(null, o); + return pselector.exec(); + } + + onDOMChanged(mutations) { + for ( const mutation of mutations ) { + for ( const added of mutation.addedNodes ) { + if ( added.nodeType !== 1 ) { continue; } + return this.proceduralFilterer.uBOL_DOMChanged(); + } + for ( const removed of mutation.removedNodes ) { + if ( removed.nodeType !== 1 ) { continue; } + return this.proceduralFilterer.uBOL_DOMChanged(); + } + } + } +}; + +/******************************************************************************/ + +})(); + +void 0; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/css-procedural.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-procedural.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/css-procedural.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-procedural.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,10 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -/******************************************************************************/ - // Important! // Isolate from global scope (function uBOL_cssProcedural() { @@ -31,798 +27,110 @@ const proceduralImports = self.proceduralImports || []; self.proceduralImports = undefined; -delete self.proceduralImports; /******************************************************************************/ -const hnParts = []; -try { hnParts.push(...document.location.hostname.split('.')); } -catch(ex) { } -const hnpartslen = hnParts.length; -if ( hnpartslen === 0 ) { return; } - const selectors = []; +const exceptions = []; -for ( const { argsList, exceptionsMap, hostnamesMap, entitiesMap } of proceduralImports ) { - const todoIndices = new Set(); - const tonotdoIndices = []; - // Exceptions - if ( exceptionsMap.size !== 0 ) { - for ( let i = 0; i < hnpartslen; i++ ) { - const hn = hnParts.slice(i).join('.'); - const excepted = exceptionsMap.get(hn); - if ( excepted ) { tonotdoIndices.push(...excepted); } - } - exceptionsMap.clear(); - } - // Hostname-based - if ( hostnamesMap.size !== 0 ) { - const collectArgIndices = hn => { - let argsIndices = hostnamesMap.get(hn); - if ( argsIndices === undefined ) { return; } - if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; } - for ( const argsIndex of argsIndices ) { - if ( tonotdoIndices.includes(argsIndex) ) { continue; } - todoIndices.add(argsIndex); - } - }; - for ( let i = 0; i < hnpartslen; i++ ) { - const hn = hnParts.slice(i).join('.'); - collectArgIndices(hn); - } - collectArgIndices('*'); - hostnamesMap.clear(); +const lookupHostname = (hostname, details, out) => { + let seqi = details.hostnamesMap.get(hostname); + if ( seqi === undefined ) { return; } + const { argsList, argsSeqs } = details; + for (;;) { + const argi = argsSeqs[seqi++]; + const done = argi > 0; + out.push(...JSON.parse(argsList[done ? argi : -argi])); + if ( done ) { break; } } - // Entity-based - if ( entitiesMap.size !== 0 ) { - const n = hnpartslen - 1; - for ( let i = 0; i < n; i++ ) { - for ( let j = n; j > i; j-- ) { - const en = hnParts.slice(i,j).join('.'); - let argsIndices = entitiesMap.get(en); - if ( argsIndices === undefined ) { continue; } - if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; } - for ( const argsIndex of argsIndices ) { - if ( tonotdoIndices.includes(argsIndex) ) { continue; } - todoIndices.add(argsIndex); - } - } - } - entitiesMap.clear(); - } - for ( const i of todoIndices ) { - selectors.push(...argsList[i].map(json => JSON.parse(json))); - } - argsList.length = 0; -} -proceduralImports.length = 0; - -if ( selectors.length === 0 ) { return; } - -/******************************************************************************/ - -const uBOL_injectCSS = (css, count = 10) => { - chrome.runtime.sendMessage({ what: 'insertCSS', css }).catch(( ) => { - count -= 1; - if ( count === 0 ) { return; } - uBOL_injectCSS(css, count - 1); - }); }; -const nonVisualElements = { - head: true, - link: true, - meta: true, - script: true, - style: true, -}; - -const regexFromString = (s, exact = false) => { - if ( s === '' ) { return /^/; } - const match = /^\/(.+)\/([imu]*)$/.exec(s); - if ( match !== null ) { - return new RegExp(match[1], match[2] || undefined); +const lookupAll = hostname => { + for ( const details of proceduralImports ) { + lookupHostname(hostname, details, selectors); + const matches = []; + lookupHostname(`~${hostname}`, details, matches); + if ( matches.length === 0 ) { continue; } + exceptions.push(...matches.map(a => JSON.stringify(a))); } - const reStr = s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - return new RegExp(exact ? `^${reStr}$` : reStr); }; -/******************************************************************************/ - -// 'P' stands for 'Procedural' - -class PSelectorTask { - begin() { - } - end() { - } -} - -/******************************************************************************/ - -class PSelectorVoidTask extends PSelectorTask { - constructor(task) { - super(); - console.info(`uBO: :${task[0]}() operator does not exist`); - } - transpose() { - } -} - -/******************************************************************************/ - -class PSelectorHasTextTask extends PSelectorTask { - constructor(task) { - super(); - this.needle = regexFromString(task[1]); - } - transpose(node, output) { - if ( this.needle.test(node.textContent) ) { - output.push(node); - } - } -} - -/******************************************************************************/ - -class PSelectorIfTask extends PSelectorTask { - constructor(task) { - super(); - this.pselector = new PSelector(task[1]); - } - transpose(node, output) { - if ( this.pselector.test(node) === this.target ) { - output.push(node); - } - } -} -PSelectorIfTask.prototype.target = true; - -class PSelectorIfNotTask extends PSelectorIfTask { -} -PSelectorIfNotTask.prototype.target = false; - -/******************************************************************************/ - -class PSelectorMatchesAttrTask extends PSelectorTask { - constructor(task) { - super(); - this.reAttr = regexFromString(task[1].attr, true); - this.reValue = regexFromString(task[1].value, true); - } - transpose(node, output) { - const attrs = node.getAttributeNames(); - for ( const attr of attrs ) { - if ( this.reAttr.test(attr) === false ) { continue; } - if ( this.reValue.test(node.getAttribute(attr)) === false ) { continue; } - output.push(node); - } - } -} - -/******************************************************************************/ +self.isolatedAPI.forEachHostname(lookupAll, { + hasEntities: proceduralImports.some(a => a.hasEntities) +}); +proceduralImports.length = 0; -class PSelectorMatchesCSSTask extends PSelectorTask { - constructor(task) { - super(); - this.name = task[1].name; - this.pseudo = task[1].pseudo ? `::${task[1].pseudo}` : null; - let arg0 = task[1].value, arg1; - if ( Array.isArray(arg0) ) { - arg1 = arg0[1]; arg0 = arg0[0]; - } - this.value = new RegExp(arg0, arg1); - } - transpose(node, output) { - const style = window.getComputedStyle(node, this.pseudo); - if ( style !== null && this.value.test(style[this.name]) ) { - output.push(node); - } - } -} -class PSelectorMatchesCSSAfterTask extends PSelectorMatchesCSSTask { - constructor(task) { - super(task); - this.pseudo = '::after'; - } -} +if ( selectors.length === 0 ) { return; } -class PSelectorMatchesCSSBeforeTask extends PSelectorMatchesCSSTask { - constructor(task) { - super(task); - this.pseudo = '::before'; +const exceptedSelectors = exceptions.length !== 0 + ? selectors.filter(a => exceptions.includes(JSON.stringify(a)) === false) + : selectors; +if ( exceptedSelectors.length === 0 ) { return; } + +const declaratives = exceptedSelectors.filter(a => a.cssable); +if ( declaratives.length !== 0 ) { + const cssRuleFromProcedural = details => { + const { tasks, action } = details; + let mq, selector; + if ( Array.isArray(tasks) ) { + if ( tasks[0][0] !== 'matches-media' ) { return; } + mq = tasks[0][1]; + if ( tasks.length > 2 ) { return; } + if ( tasks.length === 2 ) { + if ( tasks[1][0] !== 'spath' ) { return; } + selector = tasks[1][1]; + } + } + let style; + if ( Array.isArray(action) ) { + if ( action[0] !== 'style' ) { return; } + selector = selector || details.selector; + style = action[1]; + } + if ( mq === undefined && style === undefined && selector === undefined ) { return; } + if ( mq === undefined ) { + return `${selector}\n{${style}}`; + } + if ( style === undefined ) { + return `@media ${mq} {\n${selector}\n{display:none!important;}\n}`; + } + return `@media ${mq} {\n${selector}\n{${style}}\n}`; + }; + const sheetText = []; + for ( const details of declaratives ) { + const ruleText = cssRuleFromProcedural(details); + if ( ruleText === undefined ) { continue; } + sheetText.push(ruleText); + } + if ( sheetText.length !== 0 ) { + self.cssAPI.insert(sheetText.join('\n')); } } -/******************************************************************************/ - -class PSelectorMatchesMediaTask extends PSelectorTask { - constructor(task) { - super(); - this.mql = window.matchMedia(task[1]); - if ( this.mql.media === 'not all' ) { return; } - this.mql.addEventListener('change', ( ) => { - if ( proceduralFilterer instanceof Object === false ) { return; } - proceduralFilterer.onDOMChanged(); +const procedurals = exceptedSelectors.filter(a => a.cssable === undefined); +if ( procedurals.length !== 0 ) { + const addSelectors = selectors => { + if ( self.listsProceduralFiltererAPI instanceof Object === false ) { return; } + self.listsProceduralFiltererAPI.addSelectors(selectors); + }; + if ( self.ProceduralFiltererAPI === undefined ) { + self.ProceduralFiltererAPI = chrome.runtime.sendMessage({ + what: 'injectCSSProceduralAPI' + }).catch(( ) => { }); } - transpose(node, output) { - if ( this.mql.matches === false ) { return; } - output.push(node); - } -} - -/******************************************************************************/ - -class PSelectorMatchesPathTask extends PSelectorTask { - constructor(task) { - super(); - this.needle = regexFromString( - task[1].replace(/\P{ASCII}/gu, s => encodeURIComponent(s)) - ); - } - transpose(node, output) { - if ( this.needle.test(self.location.pathname + self.location.search) ) { - output.push(node); - } - } -} - -/******************************************************************************/ - -class PSelectorMatchesPropTask extends PSelectorTask { - constructor(task) { - super(); - this.props = task[1].attr.split('.'); - this.reValue = task[1].value !== '' - ? regexFromString(task[1].value, true) - : null; - } - transpose(node, output) { - let value = node; - for ( const prop of this.props ) { - if ( value === undefined ) { return; } - if ( value === null ) { return; } - value = value[prop]; - } - if ( this.reValue === null ) { - if ( value === undefined ) { return; } - } else if ( this.reValue.test(value) === false ) { - return; - } - output.push(node); - } -} - -/******************************************************************************/ - -class PSelectorMinTextLengthTask extends PSelectorTask { - constructor(task) { - super(); - this.min = task[1]; - } - transpose(node, output) { - if ( node.textContent.length >= this.min ) { - output.push(node); - } - } -} - -/******************************************************************************/ - -class PSelectorOthersTask extends PSelectorTask { - constructor() { - super(); - this.targets = new Set(); - } - begin() { - this.targets.clear(); - } - end(output) { - const toKeep = new Set(this.targets); - const toDiscard = new Set(); - const body = document.body; - const head = document.head; - let discard = null; - for ( let keep of this.targets ) { - while ( keep !== null && keep !== body && keep !== head ) { - toKeep.add(keep); - toDiscard.delete(keep); - discard = keep.previousElementSibling; - while ( discard !== null ) { - if ( nonVisualElements[discard.localName] !== true ) { - if ( toKeep.has(discard) === false ) { - toDiscard.add(discard); - } - } - discard = discard.previousElementSibling; - } - discard = keep.nextElementSibling; - while ( discard !== null ) { - if ( nonVisualElements[discard.localName] !== true ) { - if ( toKeep.has(discard) === false ) { - toDiscard.add(discard); - } - } - discard = discard.nextElementSibling; - } - keep = keep.parentElement; - } - } - for ( discard of toDiscard ) { - output.push(discard); - } - this.targets.clear(); - } - transpose(candidate) { - for ( const target of this.targets ) { - if ( target.contains(candidate) ) { return; } - if ( candidate.contains(target) ) { - this.targets.delete(target); - } - } - this.targets.add(candidate); - } -} - -/******************************************************************************/ - -class PSelectorShadowTask extends PSelectorTask { - constructor(task) { - super(); - this.selector = task[1]; - } - transpose(node, output) { - const root = this.openOrClosedShadowRoot(node); - if ( root === null ) { return; } - const nodes = root.querySelectorAll(this.selector); - output.push(...nodes); - } - get openOrClosedShadowRoot() { - if ( PSelectorShadowTask.openOrClosedShadowRoot !== undefined ) { - return PSelectorShadowTask.openOrClosedShadowRoot; - } - if ( typeof chrome === 'object' && chrome !== null ) { - if ( chrome.dom instanceof Object ) { - if ( typeof chrome.dom.openOrClosedShadowRoot === 'function' ) { - PSelectorShadowTask.openOrClosedShadowRoot = - chrome.dom.openOrClosedShadowRoot; - return PSelectorShadowTask.openOrClosedShadowRoot; - } - } - } - PSelectorShadowTask.openOrClosedShadowRoot = node => - node.openOrClosedShadowRoot || null; - return PSelectorShadowTask.openOrClosedShadowRoot; - } -} - -/******************************************************************************/ - -// https://github.com/AdguardTeam/ExtendedCss/issues/31#issuecomment-302391277 -// Prepend `:scope ` if needed. -class PSelectorSpathTask extends PSelectorTask { - constructor(task) { - super(); - this.spath = task[1]; - this.nth = /^(?:\s*[+~]|:)/.test(this.spath); - if ( this.nth ) { return; } - if ( /^\s*>/.test(this.spath) ) { - this.spath = `:scope ${this.spath.trim()}`; - } - } - transpose(node, output) { - const nodes = this.nth - ? PSelectorSpathTask.qsa(node, this.spath) - : node.querySelectorAll(this.spath); - for ( const node of nodes ) { - output.push(node); - } - } - // Helper method for other operators. - static qsa(node, selector) { - const parent = node.parentElement; - if ( parent === null ) { return []; } - let pos = 1; - for (;;) { - node = node.previousElementSibling; - if ( node === null ) { break; } - pos += 1; - } - return parent.querySelectorAll( - `:scope > :nth-child(${pos})${selector}` - ); - } -} - -/******************************************************************************/ - -class PSelectorUpwardTask extends PSelectorTask { - constructor(task) { - super(); - const arg = task[1]; - if ( typeof arg === 'number' ) { - this.i = arg; - } else { - this.s = arg; - } - } - transpose(node, output) { - if ( this.s !== '' ) { - const parent = node.parentElement; - if ( parent === null ) { return; } - node = parent.closest(this.s); - if ( node === null ) { return; } - } else { - let nth = this.i; - for (;;) { - node = node.parentElement; - if ( node === null ) { return; } - nth -= 1; - if ( nth === 0 ) { break; } - } - } - output.push(node); - } -} -PSelectorUpwardTask.prototype.i = 0; -PSelectorUpwardTask.prototype.s = ''; - -/******************************************************************************/ - -class PSelectorWatchAttrs extends PSelectorTask { - constructor(task) { - super(); - this.observer = null; - this.observed = new WeakSet(); - this.observerOptions = { - attributes: true, - subtree: true, - }; - const attrs = task[1]; - if ( Array.isArray(attrs) && attrs.length !== 0 ) { - this.observerOptions.attributeFilter = task[1]; - } - } - // TODO: Is it worth trying to re-apply only the current selector? - handler() { - if ( proceduralFilterer instanceof Object ) { - proceduralFilterer.onDOMChanged(); - } - } - transpose(node, output) { - output.push(node); - if ( this.observed.has(node) ) { return; } - if ( this.observer === null ) { - this.observer = new MutationObserver(this.handler); - } - this.observer.observe(node, this.observerOptions); - this.observed.add(node); - } -} - -/******************************************************************************/ - -class PSelectorXpathTask extends PSelectorTask { - constructor(task) { - super(); - this.xpe = document.createExpression(task[1], null); - this.xpr = null; - } - transpose(node, output) { - this.xpr = this.xpe.evaluate( - node, - XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, - this.xpr - ); - let j = this.xpr.snapshotLength; - while ( j-- ) { - const node = this.xpr.snapshotItem(j); - if ( node.nodeType === 1 ) { - output.push(node); - } - } - } -} - -/******************************************************************************/ - -class PSelector { - constructor(o) { - this.selector = o.selector; - this.tasks = []; - const tasks = []; - if ( Array.isArray(o.tasks) === false ) { return; } - for ( const task of o.tasks ) { - const ctor = this.operatorToTaskMap.get(task[0]) || PSelectorVoidTask; - tasks.push(new ctor(task)); - } - this.tasks = tasks; - } - prime(input) { - const root = input || document; - if ( this.selector === '' ) { return [ root ]; } - if ( input !== document ) { - const c0 = this.selector.charCodeAt(0); - if ( c0 === 0x2B /* + */ || c0 === 0x7E /* ~ */ ) { - return Array.from(PSelectorSpathTask.qsa(input, this.selector)); - } else if ( c0 === 0x3E /* > */ ) { - return Array.from(input.querySelectorAll(`:scope ${this.selector}`)); - } - } - return Array.from(root.querySelectorAll(this.selector)); - } - exec(input) { - let nodes = this.prime(input); - for ( const task of this.tasks ) { - if ( nodes.length === 0 ) { break; } - const transposed = []; - task.begin(); - for ( const node of nodes ) { - task.transpose(node, transposed); - } - task.end(transposed); - nodes = transposed; - } - return nodes; - } - test(input) { - const nodes = this.prime(input); - for ( const node of nodes ) { - let output = [ node ]; - for ( const task of this.tasks ) { - const transposed = []; - task.begin(); - for ( const node of output ) { - task.transpose(node, transposed); - } - task.end(transposed); - output = transposed; - if ( output.length === 0 ) { break; } - } - if ( output.length !== 0 ) { return true; } - } - return false; - } -} -PSelector.prototype.operatorToTaskMap = new Map([ - [ 'has', PSelectorIfTask ], - [ 'has-text', PSelectorHasTextTask ], - [ 'if', PSelectorIfTask ], - [ 'if-not', PSelectorIfNotTask ], - [ 'matches-attr', PSelectorMatchesAttrTask ], - [ 'matches-css', PSelectorMatchesCSSTask ], - [ 'matches-css-after', PSelectorMatchesCSSAfterTask ], - [ 'matches-css-before', PSelectorMatchesCSSBeforeTask ], - [ 'matches-media', PSelectorMatchesMediaTask ], - [ 'matches-path', PSelectorMatchesPathTask ], - [ 'matches-prop', PSelectorMatchesPropTask ], - [ 'min-text-length', PSelectorMinTextLengthTask ], - [ 'not', PSelectorIfNotTask ], - [ 'others', PSelectorOthersTask ], - [ 'shadow', PSelectorShadowTask ], - [ 'spath', PSelectorSpathTask ], - [ 'upward', PSelectorUpwardTask ], - [ 'watch-attr', PSelectorWatchAttrs ], - [ 'xpath', PSelectorXpathTask ], -]); - -/******************************************************************************/ - -class PSelectorRoot extends PSelector { - constructor(o) { - super(o); - this.budget = 200; // I arbitrary picked a 1/5 second - this.raw = o.raw; - this.cost = 0; - this.lastAllowanceTime = 0; - this.action = o.action; - } - prime(input) { - try { - return super.prime(input); - } catch (ex) { - } - return []; - } - exec(input) { - try { - return super.exec(input); - } catch (ex) { - } - return []; - } -} - -/******************************************************************************/ - -class ProceduralFilterer { - constructor(selectors) { - this.selectors = []; - this.masterToken = this.randomToken(); - this.styleTokenMap = new Map(); - this.styledNodes = new Set(); - this.timer = undefined; - this.hideStyle = 'display:none!important;'; - this.addSelectors(selectors); - // Important: commit now (do not go through onDOMChanged) to be sure - // first pass is going to happen asap. - this.uBOL_commitNow(); - } - - addSelectors() { - for ( const selector of selectors ) { - const pselector = new PSelectorRoot(selector); - this.primeProceduralSelector(pselector); - this.selectors.push(pselector); - } - this.onDOMChanged(); - } - - // This allows to perform potentially expensive initialization steps - // before the filters are ready to be applied. - primeProceduralSelector(pselector) { - if ( pselector.action === undefined ) { - this.styleTokenFromStyle(this.hideStyle); - } else if ( pselector.action[0] === 'style' ) { - this.styleTokenFromStyle(pselector.action[1]); - } - return pselector; - } - - uBOL_commitNow() { - // https://github.com/uBlockOrigin/uBlock-issues/issues/341 - // Be ready to unhide nodes which no longer matches any of - // the procedural selectors. - const toUnstyle = this.styledNodes; - this.styledNodes = new Set(); - - let t0 = Date.now(); - - for ( const pselector of this.selectors.values() ) { - const allowance = Math.floor((t0 - pselector.lastAllowanceTime) / 2000); - if ( allowance >= 1 ) { - pselector.budget += allowance * 50; - if ( pselector.budget > 200 ) { pselector.budget = 200; } - pselector.lastAllowanceTime = t0; - } - if ( pselector.budget <= 0 ) { continue; } - const nodes = pselector.exec(); - const t1 = Date.now(); - pselector.budget += t0 - t1; - if ( pselector.budget < -500 ) { - console.info('uBOL: disabling %s', pselector.raw); - pselector.budget = -0x7FFFFFFF; - } - t0 = t1; - if ( nodes.length === 0 ) { continue; } - this.processNodes(nodes, pselector.action); - } - - this.unprocessNodes(toUnstyle); - } - - styleTokenFromStyle(style) { - if ( style === undefined ) { return; } - let styleToken = this.styleTokenMap.get(style); - if ( styleToken !== undefined ) { return styleToken; } - styleToken = this.randomToken(); - this.styleTokenMap.set(style, styleToken); - uBOL_injectCSS(`[${this.masterToken}][${styleToken}]\n{${style}}\n`); - return styleToken; - } - - processNodes(nodes, action) { - const op = action && action[0] || ''; - const arg = op !== '' ? action[1] : ''; - switch ( op ) { - case '': - /* fall through */ - case 'style': { - const styleToken = this.styleTokenFromStyle( - arg === '' ? this.hideStyle : arg - ); - for ( const node of nodes ) { - node.setAttribute(this.masterToken, ''); - node.setAttribute(styleToken, ''); - this.styledNodes.add(node); - } - break; - } - case 'remove': { - for ( const node of nodes ) { - node.remove(); - node.textContent = ''; - } - break; - } - case 'remove-attr': { - const reAttr = regexFromString(arg, true); - for ( const node of nodes ) { - for ( const name of node.getAttributeNames() ) { - if ( reAttr.test(name) === false ) { continue; } - node.removeAttribute(name); - } - } - break; - } - case 'remove-class': { - const reClass = regexFromString(arg, true); - for ( const node of nodes ) { - const cl = node.classList; - for ( const name of cl.values() ) { - if ( reClass.test(name) === false ) { continue; } - cl.remove(name); - } - } - break; - } - default: - break; - } - } - - // TODO: Current assumption is one style per hit element. Could be an - // issue if an element has multiple styling and one styling is - // brought back. Possibly too rare to care about this for now. - unprocessNodes(nodes) { - for ( const node of nodes ) { - if ( this.styledNodes.has(node) ) { continue; } - node.removeAttribute(this.masterToken); - } - } - - randomToken() { - const n = Math.random(); - return String.fromCharCode(n * 25 + 97) + - Math.floor( - (0.25 + n * 0.75) * Number.MAX_SAFE_INTEGER - ).toString(36).slice(-8); - } - - onDOMChanged() { - if ( this.timer !== undefined ) { return; } - this.timer = self.requestAnimationFrame(( ) => { - this.timer = undefined; - this.uBOL_commitNow(); + if ( self.ProceduralFiltererAPI instanceof Promise ) { + self.ProceduralFiltererAPI.then(( ) => { + self.listsProceduralFiltererAPI = new self.ProceduralFiltererAPI(); + addSelectors(procedurals); }); + } else { + addSelectors(procedurals); } } /******************************************************************************/ -const proceduralFilterer = new ProceduralFilterer(selectors); - -const observer = new MutationObserver(mutations => { - let domChanged = false; - for ( let i = 0; i < mutations.length && !domChanged; i++ ) { - const mutation = mutations[i]; - for ( const added of mutation.addedNodes ) { - if ( added.nodeType !== 1 ) { continue; } - domChanged = true; - break; - } - if ( domChanged === false ) { - for ( const removed of mutation.removedNodes ) { - if ( removed.nodeType !== 1 ) { continue; } - domChanged = true; - break; - } - } - } - if ( domChanged === false ) { return; } - proceduralFilterer.onDOMChanged(); -}); - -observer.observe(document, { - childList: true, - subtree: true, -}); - -/******************************************************************************/ - })(); -/******************************************************************************/ - void 0; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/css-specific.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-specific.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/css-specific.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-specific.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,12 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - -/******************************************************************************/ - // Important! // Isolate from global scope (function uBOL_cssSpecific() { @@ -33,88 +27,48 @@ const specificImports = self.specificImports || []; self.specificImports = undefined; -delete self.specificImports; /******************************************************************************/ -const hnParts = []; -try { hnParts.push(...document.location.hostname.split('.')); } -catch(ex) { } -const hnpartslen = hnParts.length; -if ( hnpartslen === 0 ) { return; } - const selectors = []; +const exceptions = []; -for ( const { argsList, exceptionsMap, hostnamesMap, entitiesMap } of specificImports ) { - const todoIndices = new Set(); - const tonotdoIndices = []; - // Exceptions - if ( exceptionsMap.size !== 0 ) { - for ( let i = 0; i < hnpartslen; i++ ) { - const hn = hnParts.slice(i).join('.'); - const excepted = exceptionsMap.get(hn); - if ( excepted ) { tonotdoIndices.push(...excepted); } - } - exceptionsMap.clear(); - } - // Hostname-based - if ( hostnamesMap.size !== 0 ) { - const collectArgIndices = hn => { - let argsIndices = hostnamesMap.get(hn); - if ( argsIndices === undefined ) { return; } - if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; } - for ( const argsIndex of argsIndices ) { - if ( tonotdoIndices.includes(argsIndex) ) { continue; } - todoIndices.add(argsIndex); - } - }; - for ( let i = 0; i < hnpartslen; i++ ) { - const hn = hnParts.slice(i).join('.'); - collectArgIndices(hn); - } - collectArgIndices('*'); - hostnamesMap.clear(); - } - // Entity-based - if ( entitiesMap.size !== 0 ) { - const n = hnpartslen - 1; - for ( let i = 0; i < n; i++ ) { - for ( let j = n; j > i; j-- ) { - const en = hnParts.slice(i,j).join('.'); - let argsIndices = entitiesMap.get(en); - if ( argsIndices === undefined ) { continue; } - if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; } - for ( const argsIndex of argsIndices ) { - if ( tonotdoIndices.includes(argsIndex) ) { continue; } - todoIndices.add(argsIndex); - } - } - } - entitiesMap.clear(); +const lookupHostname = (hostname, details, out) => { + let seqi = details.hostnamesMap.get(hostname); + if ( seqi === undefined ) { return; } + const { argsList, argsSeqs } = details; + for (;;) { + const argi = argsSeqs[seqi++]; + const done = argi > 0; + out.push(...argsList[done ? argi : -argi].split('\n')); + if ( done ) { break; } } - for ( const i of todoIndices ) { - selectors.push(argsList[i]); +}; + +const lookupAll = hostname => { + for ( const details of specificImports ) { + lookupHostname(hostname, details, selectors); + lookupHostname(`~${hostname}`, details, exceptions); } - argsList.length = 0; -} +}; + +self.isolatedAPI.forEachHostname(lookupAll, { + hasEntities: specificImports.some(a => a.hasEntities) +}); + specificImports.length = 0; if ( selectors.length === 0 ) { return; } -/******************************************************************************/ +const exceptedSelectors = exceptions.length !== 0 + ? selectors.filter(a => exceptions.includes(a) === false) + : selectors; +if ( exceptedSelectors.length === 0 ) { return; } -(function uBOL_injectCSS(css, count = 10) { - chrome.runtime.sendMessage({ what: 'insertCSS', css }).catch(( ) => { - count -= 1; - if ( count === 0 ) { return; } - uBOL_injectCSS(css, count - 1); - }); -})(`${selectors.join(',')}{display:none!important;}`); +self.cssAPI.insert(`${exceptedSelectors.join(',')}{display:none!important;}`); /******************************************************************************/ })(); -/******************************************************************************/ - void 0; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/css-user-terminate.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-user-terminate.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/css-user-terminate.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-user-terminate.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,45 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2019-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +(function uBOL_cssUserTerminate() { + +/******************************************************************************/ + +const plainSelectors = self.customFilters?.plainSelectors; +if ( plainSelectors ) { + chrome.runtime.sendMessage({ + what: 'removeCSS', + css: `${plainSelectors.join(',\n')}{display:none!important;}`, + }).catch(( ) => { + }); +} + +if ( self.customProceduralFiltererAPI instanceof Object ) { + self.customProceduralFiltererAPI.reset(); +} + +self.customFilters = undefined; + +/******************************************************************************/ + +})(); + +void 0; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/css-user.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-user.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/css-user.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/css-user.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,48 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2019-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +(async function uBOL_cssUser() { + +/******************************************************************************/ + +const docURL = new URL(document.baseURI); +const details = await chrome.runtime.sendMessage({ + what: 'injectCustomFilters', + hostname: docURL.hostname, +}).catch(( ) => { +}); + +if ( details?.proceduralSelectors?.length ) { + if ( self.ProceduralFiltererAPI ) { + self.customProceduralFiltererAPI = new self.ProceduralFiltererAPI(); + self.customProceduralFiltererAPI.addSelectors( + details.proceduralSelectors.map(a => JSON.parse(a)) + ); + } +} + +self.customFilters = details; + +/******************************************************************************/ + +})(); + +void 0; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/isolated-api.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/isolated-api.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/isolated-api.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/isolated-api.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,80 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2022-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock/ + +*/ + +/******************************************************************************/ + +(api => { + if ( typeof api === 'object' ) { return; } + + const isolatedAPI = self.isolatedAPI = {}; + + const hostnameStack = (( ) => { + const docloc = document.location; + const origins = [ docloc.origin ]; + if ( docloc.ancestorOrigins ) { + origins.push(...docloc.ancestorOrigins); + } + return origins.map((origin, i) => { + const beg = origin.lastIndexOf('://'); + if ( beg === -1 ) { return; } + const hn1 = origin.slice(beg+3) + const end = hn1.indexOf(':'); + const hn2 = end === -1 ? hn1 : hn1.slice(0, end); + return { hnparts: hn2.split('.'), i }; + }).filter(a => a !== undefined); + })(); + + const forEachHostname = (entry, callback, details) => { + const hnparts = entry.hnparts; + const hnpartslen = hnparts.length; + if ( hnpartslen === 0 ) { return; } + for ( let i = 0; i < hnpartslen; i++ ) { + const r = callback(`${hnparts.slice(i).join('.')}`, details); + if ( r !== undefined ) { return r; } + } + if ( details?.hasEntities !== true ) { return; } + const n = hnpartslen - 1; + for ( let i = 0; i < n; i++ ) { + for ( let j = n; j > i; j-- ) { + const r = callback(`${hnparts.slice(i,j).join('.')}.*`, details); + if ( r !== undefined ) { return r; } + } + } + }; + + isolatedAPI.forEachHostname = (callback, details) => { + if ( hostnameStack.length === 0 ) { return; } + return forEachHostname(hostnameStack[0], callback, details); + }; + + isolatedAPI.forEachHostnameAncestors = (callback, details) => { + for ( const entry of hostnameStack ) { + if ( entry.i === 0 ) { continue; } + const r = forEachHostname(entry, callback, details); + if ( r !== undefined ) { return r; } + } + }; +})(self.isolatedAPI); + +/******************************************************************************/ + +void 0; \ No newline at end of file diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/picker.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/picker.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/picker.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/picker.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,303 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +(async ( ) => { + +/******************************************************************************/ + +const ubolOverlay = self.ubolOverlay; +if ( ubolOverlay === undefined ) { return; } +if ( ubolOverlay.file === '/picker-ui.html' ) { return; } + +/******************************************************************************/ + +function attributeNameFromPart(part) { + const pos = part.search(/\^?=/); + return part.slice(1, pos); +} + +function selectorFromAddresses(partsDB, addresses) { + const selector = []; + let majorLast = -1; + for ( const address of addresses ) { + const major = address >>> 12; + if ( majorLast !== -1 ) { + const delta = majorLast - major; + if ( delta > 1 ) { + selector.push(' '); + } else if ( delta === 1 ) { + selector.push(' > '); + } + } + majorLast = major; + const part = partsDB.get(address); + selector.push( + (address & 0xF) === 3 + ? `[${attributeNameFromPart(part)}]` + : part + ); + } + return selector.join(''); +} + +/******************************************************************************* + * + * Selector part address: + * 0b00000000_00000000_0000 + * | | | + * | | +-- 4-bit: Descriptor + * | +------- 8-bit: Part index + * +---------------- 8-bit: List index + * Descriptor: + * - 0: tag name + * - 1: id + * - 2: class + * - 3: attribute + * - 4: :nth-of-type + * List index: 0 is deepest + * + * Selector part addresses are used to reference parts in associated database. + * + * */ + +function candidatesAtPoint(x, y) { + // We need at least one element. + let elem = null; + if ( typeof x === 'number' ) { + elem = ubolOverlay.elementFromPoint(x, y); + } else if ( x instanceof HTMLElement ) { + elem = x; + x = undefined; + } + + const partsDB = new Map(); + const listParts = []; + while ( elem && elem !== document.body ) { + const tagName = elem.localName; + const addressMajor = listParts.length << 12; + partsDB.set(addressMajor, CSS.escape(tagName)); + const parts = [ addressMajor ]; + // Id + if ( typeof elem.id === 'string' && elem.id !== '' ) { + const address = addressMajor | parts.length << 4 | 1; + partsDB.set(address, `#${CSS.escape(elem.id)}`); + parts.push(address); + } + // Classes + for ( const name of elem.classList.values() ) { + const address = addressMajor | parts.length << 4 | 2; + partsDB.set(address, `.${CSS.escape(name)}`); + parts.push(address); + } + // Attributes + for ( const name of elem.getAttributeNames() ) { + if ( name === 'id' || name === 'class' ) { continue; } + if ( excludedAttributeExpansion.includes(name) ) { + const address = addressMajor | parts.length << 4 | 3; + partsDB.set(address, `[${CSS.escape(name)}]`); + parts.push(address); + continue; + } + let value = elem.getAttribute(name); + const pos = value.search(/[\n\r]/); + if ( pos !== -1 ) { + value = value.slice(0, pos); + } + const address = addressMajor | parts.length << 4 | 3; + partsDB.set(address, `[${CSS.escape(name)}="${value}"]`); + parts.push(address); + } + // https://github.com/chrisaljoudi/uBlock/issues/637 + // If the selector is still ambiguous at this point, further narrow + // using `:nth-of-type`. + const parentNode = elem.parentNode; + if ( ubolOverlay.qsa(parentNode, `:scope > ${selectorFromAddresses(partsDB, parts)}`).length > 1 ) { + let i = 1; + while ( elem.previousSibling !== null ) { + elem = elem.previousSibling; + if ( typeof elem.localName !== 'string' ) { continue; } + if ( elem.localName !== tagName ) { continue; } + i++; + } + const address = addressMajor | parts.length << 4 | 4; + partsDB.set(address, `:nth-of-type(${i})`); + parts.push(address); + } + listParts.push(parts); + elem = elem.parentElement; + } + if ( listParts.length === 0 ) { return; } + + const sliderCandidates = []; + for ( let i = 0, n = listParts.length; i < n; i++ ) { + sliderCandidates.push(listParts[i]); + for ( let j = i + 1; j < n; j++ ) { + sliderCandidates.push([ + ...listParts[j], + ...sliderCandidates.at(-1), + ]); + } + } + const sliderMap = new Map(); + for ( const candidates of sliderCandidates ) { + if ( candidates.some(a => (a & 0xF) === 1) ) { + const selectorPath = candidates.filter(a => (a & 0xF) === 1); + sliderMap.set(JSON.stringify(selectorPath), 0); + } else if ( candidates.some(a => (a & 0xF) === 4) ) { + const selectorPath = candidates.filter(a => { + return a &= 0xF, a === 0 || a === 4; + }); + sliderMap.set(JSON.stringify(selectorPath), 0); + } + if ( candidates.some(a => (a & 0xF) === 2) ) { + const selectorPath = candidates.filter(a => { + return a &= 0xF, a === 0 || a === 2; + }); + sliderMap.set(JSON.stringify(selectorPath), 0); + } + const selectorPath = candidates.filter(a => { + return a &= 0xF, a === 0 || a === 3; + }); + sliderMap.set(JSON.stringify(selectorPath), 0); + } + sliderMap.delete('[]'); + const elemToIdMap = new Map(); + const resultSetMap = new Map(); + let elemId = 1; + for ( const json of sliderMap.keys() ) { + const addresses = JSON.parse(json); + const selector = selectorFromAddresses(partsDB, addresses); + if ( excludedSelectors.includes(selector) ) { continue; } + const elems = ubolOverlay.qsa(document, selector); + if ( elems.length === 0 ) { continue; } + const resultSet = []; + for ( const elem of elems ) { + if ( elemToIdMap.has(elem) === false ) { + elemToIdMap.set(elem, elemId++); + } + resultSet.push(elemToIdMap.get(elem)); + } + const resultSetKey = JSON.stringify(resultSet.sort()); + const current = resultSetMap.get(resultSetKey); + if ( current ) { + if ( current.length < addresses.length ) { continue; } + if ( current.length === addresses.length ) { + if ( addresses.some(a => (a & 0xF) === 2) === false ) { + if ( current.some(a => (a & 0xF) === 2) ) { continue; } + } + } + } + resultSetMap.set(resultSetKey, addresses); + } + const sliderParts = Array.from(resultSetMap).toSorted((a, b) => { + let amajor = a[1].at(-1) >>> 12; + let bmajor = b[1].at(-1) >>> 12; + if ( amajor !== bmajor ) { return bmajor - amajor; } + amajor = a[1].at(0) >>> 12; + bmajor = b[1].at(0) >>> 12; + if ( amajor !== bmajor ) { return bmajor - amajor; } + if ( a[0].length !== b[0].length ) { + return b[0].length - a[0].length; + } + return b[1].length - a[1].length; + }).map(a => a[1]); + return { + partsDB: Array.from(partsDB), + listParts, + sliderParts, + }; +} + +const excludedAttributeExpansion = [ + 'sizes', + 'srcset', +]; +const excludedSelectors = [ + 'div', + 'span', +]; + +/******************************************************************************/ + +async function previewSelector(selector) { + if ( selector === previewedSelector ) { return; } + if ( previewedSelector !== '' ) { + if ( previewedSelector.startsWith('{') ) { + if ( self.pickerProceduralFilteringAPI ) { + await self.pickerProceduralFilteringAPI.reset(); + } + } + if ( previewedCSS !== '' ) { + await ubolOverlay.sendMessage({ what: 'removeCSS', css: previewedCSS }); + previewedCSS = ''; + } + } + previewedSelector = selector || ''; + if ( selector === '' ) { return; } + if ( selector.startsWith('{') ) { + if ( self.ProceduralFiltererAPI === undefined ) { return; } + if ( self.pickerProceduralFilteringAPI === undefined ) { + self.pickerProceduralFilteringAPI = new self.ProceduralFiltererAPI(); + } + self.pickerProceduralFilteringAPI.addSelectors([ JSON.parse(selector) ]); + return; + } + previewedCSS = `${selector}{display:none!important;}`; + await ubolOverlay.sendMessage({ what: 'insertCSS', css: previewedCSS }); +} + +let previewedSelector = ''; +let previewedCSS = ''; + +/******************************************************************************/ + +const previewProceduralFiltererAPI = new self.ProceduralFiltererAPI(); + +/******************************************************************************/ + +function onMessage(msg) { + switch ( msg.what ) { + case 'quitTool': + previewProceduralFiltererAPI.reset(); + break; + case 'startCustomFilters': + return ubolOverlay.sendMessage({ what: 'startCustomFilters' }); + case 'terminateCustomFilters': + return ubolOverlay.sendMessage({ what: 'terminateCustomFilters' }); + case 'candidatesAtPoint': + return candidatesAtPoint(msg.mx, msg.my, msg.broad); + case 'previewSelector': + return previewSelector(msg.selector); + default: + break; + } +} + +/******************************************************************************/ + +await ubolOverlay.install('/picker-ui.html', onMessage); + +/******************************************************************************/ + +})(); + + +void 0; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/tool-overlay.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/tool-overlay.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/tool-overlay.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/tool-overlay.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,367 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +(function uBOLOverlay() { + +/******************************************************************************/ + +if ( self.ubolOverlay ) { + self.ubolOverlay.stop(); + self.ubolOverlay = undefined; +} + +self.ubolOverlay = { + file: '', + webext: typeof browser === 'object' ? browser : chrome, + url: new URL(document.baseURI), + port: null, + highlightedElements: [], + secretAttr: (( ) => { + let secret = String.fromCharCode((Math.random() * 26) + 97); + do { + secret += (Math.floor(Math.random() * 2147483647) + 2147483647) + .toString(36) + .slice(2); + } while ( secret.length < 8 ); + return secret; + })(), + + start() { + const cssStyle = [ + 'background: transparent', + 'border: 0', + 'border-radius: 0', + 'box-shadow: none', + 'color-scheme: light dark', + 'display: block', + 'filter: none', + 'height: 100vh', + ' height: 100svh', + 'left: 0', + 'margin: 0', + 'max-height: none', + 'max-width: none', + 'min-height: unset', + 'min-width: unset', + 'opacity: 1', + 'outline: 0', + 'padding: 0', + 'pointer-events: auto', + 'position: fixed', + 'top: 0', + 'transform: none', + 'visibility: hidden', + 'width: 100%', + 'z-index: 2147483647', + '' + ].join(' !important;\n'); + this.pickerCSS = [ + `:root > [${this.secretAttr}] { ${cssStyle} }`, + `:root > [${this.secretAttr}-loaded] { visibility: visible !important; }`, + `:root > [${this.secretAttr}-click] { pointer-events: none !important; }`, + ].join('\n'); + this.sendMessage({ what: 'insertCSS', css: this.pickerCSS }); + self.addEventListener('scroll', this.onViewportChanged, { passive: true }); + self.addEventListener('resize', this.onViewportChanged, { passive: true }); + self.addEventListener('keydown', this.onKeyPressed, true); + }, + + stop() { + if ( this.pickerCSS ) { + this.sendMessage({ what: 'removeCSS', css: this.pickerCSS }); + this.pickerCSS = undefined; + } + self.removeEventListener('scroll', this.onViewportChanged, { passive: true }); + self.removeEventListener('resize', this.onViewportChanged, { passive: true }); + self.removeEventListener('keydown', this.onKeyPressed, true); + if ( this.frame ) { + this.frame.remove(); + this.frame = null; + } + if ( this.port ) { + this.port.close(); + this.port.onmessage = null; + this.port.onmessageerror = null; + this.port = null; + } + this.onmessage = null; + self.ubolOverlay = undefined; + }, + + onViewportChanged() { + self.ubolOverlay.highlightUpdate(); + }, + + onKeyPressed(ev) { + if ( ev.key !== 'Escape' && ev.which !== 27 ) { return; } + ev.stopPropagation(); + ev.preventDefault(); + if ( self.ubolOverlay.onmessage ) { + self.ubolOverlay.onmessage({ what: 'quitTool' }); + } + }, + + sendMessage(msg) { + try { + return this.webext.runtime.sendMessage(msg).catch(( ) => { }); + } catch { + } + }, + + onMessage(wrapped) { + // Response to script-initiated message? + if ( typeof wrapped?.fromScriptId === 'number' ) { + const resolve = this.pendingMessages.get(wrapped.fromScriptId); + if ( resolve ) { + this.pendingMessages.delete(wrapped.fromScriptId); + resolve(wrapped.msg); + } + return; + } + const onmessage = this.onmessage; + const msg = wrapped.msg || wrapped; + let response; + switch ( msg.what ) { + case 'startTool': + this.start(); + break; + case 'quitTool': + this.stop(); + break; + case 'highlightElementAtPoint': + this.highlightElementAtPoint(msg.mx, msg.my); + break; + case 'highlightFromSelector': { + const { elems, error } = this.elementsFromSelector(msg.selector); + this.highlightElements(elems); + if ( msg.scrollTo && elems.length !== 0 ) { + elems[0].scrollIntoView({ block: 'nearest', inline: 'nearest' }); + } + response = { count: elems.length, error }; + break; + } + case 'unhighlight': + this.unhighlight(); + break; + } + response = onmessage && onmessage(msg) || response; + // Send response if this is frame-initiated message + if ( wrapped?.fromFrameId && this.port ) { + const { fromFrameId } = wrapped; + if ( response instanceof Promise ) { + response.then(response => { + if ( this.port === null ) { return; } + this.port.postMessage({ fromFrameId, msg: response }); + }); + } else { + this.port.postMessage({ fromFrameId, msg: response }); + } + } + }, + postMessage(msg) { + if ( this.port === null ) { return; } + const wrapped = { + fromScriptId: this.messageId++, + msg, + }; + return new Promise(resolve => { + this.pendingMessages.set(wrapped.fromScriptId, resolve); + this.port.postMessage(wrapped); + }); + }, + messageId: 1, + pendingMessages: new Map(), + + getElementBoundingClientRect(elem) { + let rect = typeof elem.getBoundingClientRect === 'function' + ? elem.getBoundingClientRect() + : { height: 0, left: 0, top: 0, width: 0 }; + + // https://github.com/gorhill/uBlock/issues/1024 + // Try not returning an empty bounding rect. + if ( rect.width !== 0 && rect.height !== 0 ) { + return rect; + } + if ( elem.shadowRoot instanceof DocumentFragment ) { + return this.getElementBoundingClientRect(elem.shadowRoot); + } + let left = rect.left, + right = left + rect.width, + top = rect.top, + bottom = top + rect.height; + for ( const child of elem.children ) { + rect = this.getElementBoundingClientRect(child); + if ( rect.width === 0 || rect.height === 0 ) { continue; } + if ( rect.left < left ) { left = rect.left; } + if ( rect.right > right ) { right = rect.right; } + if ( rect.top < top ) { top = rect.top; } + if ( rect.bottom > bottom ) { bottom = rect.bottom; } + } + return { + left, right, + top, bottom, + width: right - left, + height: bottom - top, + }; + }, + + highlightUpdate() { + const ow = self.innerWidth; + const oh = self.innerHeight; + const islands = []; + for ( const elem of this.highlightedElements ) { + const rect = this.getElementBoundingClientRect(elem); + // Ignore offscreen areas + if ( rect.left > ow ) { continue; } + if ( rect.top > oh ) { continue; } + if ( rect.left + rect.width < 0 ) { continue; } + if ( rect.top + rect.height < 0 ) { continue; } + islands.push( + `M${rect.left} ${rect.top}h${rect.width}v${rect.height}h-${rect.width}z` + ); + } + this.port.postMessage({ + what: 'svgPaths', + ocean: `M0 0h${ow}v${oh}h-${ow}z`, + islands: islands.join(''), + }); + }, + + highlightElements(iter = []) { + this.highlightedElements = + Array.from(iter).filter(a => + a instanceof Element && a !== this.frame + ); + this.highlightUpdate(); + }, + + qsa(node, selector) { + if ( node === null ) { return []; } + if ( selector.startsWith('{') ) { + if ( this.proceduralFiltererAPI === undefined ) { + if ( self.ProceduralFiltererAPI === undefined ) { return []; } + this.proceduralFiltererAPI = new self.ProceduralFiltererAPI(); + } + return this.proceduralFiltererAPI.qsa(selector); + } + selector = selector.replace(/::[^:]+$/, ''); + try { + const elems = node.querySelectorAll(selector); + this.qsa.error = undefined; + return elems; + } catch (reason) { + this.qsa.error = `${reason}`; + } + return []; + }, + + elementFromPoint(x, y) { + if ( x !== undefined ) { + this.lastX = x; this.lastY = y; + } else if ( this.lastX !== undefined ) { + x = this.lastX; y = this.lastY; + } else { + return null; + } + const magicAttr = `${this.secretAttr}-click`; + this.frame.setAttribute(magicAttr, ''); + let elem = document.elementFromPoint(x, y); + if ( elem === document.body || elem === document.documentElement ) { + elem = null; + } + // https://github.com/uBlockOrigin/uBlock-issues/issues/380 + this.frame.removeAttribute(magicAttr); + return elem; + }, + + elementsFromSelector(selector) { + const elems = this.qsa(document, selector); + return { elems, error: this.qsa.error }; + }, + + highlightElementAtPoint(x, y) { + const elem = self.ubolOverlay.elementFromPoint(x, y); + this.highlightElements([ elem ]); + }, + + unhighlight() { + this.highlightElements([]); + }, + + async install(file, onmessage) { + this.file = file; + const dynamicURL = new URL(this.webext.runtime.getURL(file)); + return new Promise(resolve => { + const frame = document.createElement('iframe'); + const secretAttr = this.secretAttr; + frame.setAttribute(secretAttr, ''); + const onLoad = ( ) => { + frame.onload = null; + frame.setAttribute(`${secretAttr}-loaded`, ''); + const channel = new MessageChannel(); + const port = channel.port1; + port.onmessage = ev => { + self.ubolOverlay && + self.ubolOverlay.onMessage(ev.data || {}) + }; + port.onmessageerror = ( ) => { + self.ubolOverlay && + self.ubolOverlay.onMessage({ what: 'quitTool' }) + }; + const realURL = new URL(dynamicURL); + realURL.hostname = + self.ubolOverlay.webext.i18n.getMessage('@@extension_id'); + frame.contentWindow.postMessage( + { + what: 'startOverlay', + url: document.baseURI, + width: self.innerWidth, + height: self.innerHeight, + }, + realURL.origin, + [ channel.port2 ] + ); + frame.contentWindow.focus(); + self.ubolOverlay.onmessage = onmessage; + self.ubolOverlay.port = port; + self.ubolOverlay.frame = frame; + resolve(true); + }; + if ( dynamicURL.protocol !== 'safari-web-extension:' ) { + frame.onload = ( ) => { + frame.onload = onLoad; + frame.contentWindow.location = dynamicURL.href; + }; + } else { + frame.onload = onLoad; + frame.setAttribute('src', dynamicURL.href); + } + document.documentElement.append(frame); + }); + }, +}; + +/******************************************************************************/ + +})(); + + +void 0; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/toolbar-icon.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/toolbar-icon.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/toolbar-icon.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/toolbar-icon.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,27 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +(function uBOL_toggleToolbarIcon() { + chrome.runtime.sendMessage({ + what: 'toggleToolbarIcon', + }).catch(( ) => { + }); +})(); diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/unpicker.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/unpicker.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/unpicker.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/unpicker.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,57 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +(async ( ) => { + +/******************************************************************************/ + +const ubolOverlay = self.ubolOverlay; +if ( ubolOverlay === undefined ) { return; } +if ( ubolOverlay.file === '/unpicker-ui.html' ) { return; } + +/******************************************************************************/ + +function onMessage(msg) { + switch ( msg.what ) { + case 'startCustomFilters': + return ubolOverlay.sendMessage({ what: 'startCustomFilters' }); + case 'terminateCustomFilters': + return ubolOverlay.sendMessage({ what: 'terminateCustomFilters' }); + case 'removeCustomFilters': + return ubolOverlay.sendMessage({ what: 'removeCustomFilters', + hostname: ubolOverlay.url.hostname, + selectors: [ msg.selector ], + }); + default: + break; + } +} + +/******************************************************************************/ + +await ubolOverlay.install('/unpicker-ui.html', onMessage); + +/******************************************************************************/ + +})(); + + +void 0; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/zapper.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/zapper.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting/zapper.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting/zapper.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,138 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +(async ( ) => { + +/******************************************************************************/ + +const ubolOverlay = self.ubolOverlay; +if ( ubolOverlay === undefined ) { return; } +if ( ubolOverlay.file === '/zapper-ui.html' ) { return; } + +/******************************************************************************/ + +// https://www.reddit.com/r/uBlockOrigin/comments/bktxtb/scrolling_doesnt_work/emn901o +// Override 'fixed' position property on body element if present. + +// With touch-driven devices, first highlight the element and remove only +// when tapping again the highlighted area. + +function zapElementAtPoint(mx, my, options) { + if ( options.highlight ) { + const elem = ubolOverlay.elementFromPoint(mx, my); + if ( elem ) { + ubolOverlay.highlightElements([ elem ]); + } + return; + } + + let elemToRemove = ubolOverlay.highlightedElements?.[0] ?? null; + if ( elemToRemove === null && mx !== undefined ) { + elemToRemove = ubolOverlay.elementFromPoint(mx, my); + } + + if ( elemToRemove instanceof Element === false ) { return; } + + const getStyleValue = (elem, prop) => { + const style = window.getComputedStyle(elem); + return style ? style[prop] : ''; + }; + + // Heuristic to detect scroll-locking: remove such lock when detected. + let maybeScrollLocked = elemToRemove.shadowRoot instanceof DocumentFragment; + if ( maybeScrollLocked === false ) { + let elem = elemToRemove; + do { + maybeScrollLocked = + parseInt(getStyleValue(elem, 'zIndex'), 10) >= 1000 || + getStyleValue(elem, 'position') === 'fixed'; + elem = elem.parentElement; + } while ( elem !== null && maybeScrollLocked === false ); + } + if ( maybeScrollLocked ) { + const doc = document; + if ( getStyleValue(doc.body, 'overflowY') === 'hidden' ) { + doc.body.style.setProperty('overflow', 'auto', 'important'); + } + if ( getStyleValue(doc.body, 'position') === 'fixed' ) { + doc.body.style.setProperty('position', 'initial', 'important'); + } + if ( getStyleValue(doc.documentElement, 'position') === 'fixed' ) { + doc.documentElement.style.setProperty('position', 'initial', 'important'); + } + if ( getStyleValue(doc.documentElement, 'overflowY') === 'hidden' ) { + doc.documentElement.style.setProperty('overflow', 'auto', 'important'); + } + } + elemToRemove.remove(); + ubolOverlay.highlightElementAtPoint(mx, my); +} + +/******************************************************************************/ + +function onKeyPressed(ev) { + if ( ev.key !== 'Delete' && ev.key !== 'Backspace' ) { return; } + ev.stopPropagation(); + ev.preventDefault(); + zapElementAtPoint(); +} + +/******************************************************************************/ + +function startZapper() { + self.addEventListener('keydown', onKeyPressed, true); +} + +function quitZapper() { + self.removeEventListener('keydown', onKeyPressed, true); +} + +/******************************************************************************/ + +function onMessage(msg) { + switch ( msg.what ) { + case 'startTool': + startZapper(); + break; + case 'quitTool': + quitZapper(); + break; + case 'zapElementAtPoint': + zapElementAtPoint(msg.mx, msg.my, msg.options); + if ( msg.options.highlight !== true && msg.options.stay !== true ) { + quitZapper(); + } + break; + default: + break; + } +} + +/******************************************************************************/ + +await ubolOverlay.install('/zapper-ui.html', onMessage); + +/******************************************************************************/ + +})(); + + +void 0; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting-manager.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting-manager.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/scripting-manager.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/scripting-manager.js 2025-10-25 19:32:51.000000000 +0000 @@ -21,16 +21,17 @@ import * as ut from './utils.js'; -import { browser } from './ext.js'; +import { browser, localRemove } from './ext.js'; +import { ubolErr, ubolLog } from './debug.js'; + import { fetchJSON } from './fetch.js'; import { getEnabledRulesetsDetails } from './ruleset-manager.js'; import { getFilteringModeDetails } from './mode-manager.js'; -import { ubolLog } from './debug.js'; +import { registerCustomFilters } from './filter-manager.js'; +import { registerToolbarIconToggler } from './action.js'; /******************************************************************************/ -const isGecko = browser.runtime.getURL('').startsWith('moz-extension://'); - const resourceDetailPromises = new Map(); function getScriptletDetails() { @@ -55,15 +56,13 @@ /******************************************************************************/ -// Important: We need to sort the arrays for fast comparison -const arrayEq = (a = [], b = [], sort = true) => { - const alen = a.length; - if ( alen !== b.length ) { return false; } - if ( sort ) { a.sort(); b.sort(); } - for ( let i = 0; i < alen; i++ ) { - if ( a[i] !== b[i] ) { return false; } +const normalizeMatches = matches => { + if ( matches.length <= 1 ) { return; } + if ( matches.includes('') === false ) { + if ( matches.includes('*://*/*') === false ) { return; } } - return true; + matches.length = 0; + matches.push(''); }; /******************************************************************************/ @@ -95,11 +94,17 @@ const { before, filteringModeDetails, rulesetsDetails } = context; const excludeHostnames = []; + const includeHostnames = []; const css = []; for ( const details of rulesetsDetails ) { const hostnames = genericDetails.get(details.id); - if ( hostnames !== undefined ) { - excludeHostnames.push(...hostnames); + if ( hostnames ) { + if ( hostnames.unhide ) { + excludeHostnames.push(...hostnames.unhide); + } + if ( hostnames.hide ) { + includeHostnames.push(...hostnames.hide); + } } const count = details.css?.generichigh || 0; if ( count === 0 ) { continue; } @@ -140,9 +145,12 @@ id: 'css-generichigh', css, matches, - excludeMatches, + allFrames: true, runAt: 'document_end', }; + if ( excludeMatches.length !== 0 ) { + directive.excludeMatches = excludeMatches; + } // register if ( registered === undefined ) { @@ -152,9 +160,9 @@ // update if ( - arrayEq(registered.css, css, false) === false || - arrayEq(registered.matches, matches) === false || - arrayEq(registered.excludeMatches, excludeMatches) === false + ut.strArrayEq(registered.css, css, false) === false || + ut.strArrayEq(registered.matches, matches) === false || + ut.strArrayEq(registered.excludeMatches, excludeMatches) === false ) { context.toRemove.push('css-generichigh'); context.toAdd.push(directive); @@ -166,12 +174,18 @@ function registerGeneric(context, genericDetails) { const { before, filteringModeDetails, rulesetsDetails } = context; - const excludeHostnames = []; + const excludedByFilter = []; + const includedByFilter = []; const js = []; for ( const details of rulesetsDetails ) { const hostnames = genericDetails.get(details.id); - if ( hostnames !== undefined ) { - excludeHostnames.push(...hostnames); + if ( hostnames ) { + if ( hostnames.unhide ) { + excludedByFilter.push(...hostnames.unhide); + } + if ( hostnames.hide ) { + includedByFilter.push(...hostnames.hide); + } } const count = details.css?.generic || 0; if ( count === 0 ) { continue; } @@ -180,127 +194,106 @@ if ( js.length === 0 ) { return; } + js.unshift('/js/scripting/css-api.js', '/js/scripting/isolated-api.js'); js.push('/js/scripting/css-generic.js'); const { none, basic, optimal, complete } = filteringModeDetails; - const matches = []; - const excludeMatches = []; - if ( complete.has('all-urls') ) { - excludeMatches.push(...ut.matchesFromHostnames(none)); - excludeMatches.push(...ut.matchesFromHostnames(basic)); - excludeMatches.push(...ut.matchesFromHostnames(optimal)); - excludeMatches.push(...ut.matchesFromHostnames(excludeHostnames)); - matches.push(''); - } else { - matches.push( + const includedByMode = [ ...complete ]; + const excludedByMode = [ ...none, ...basic, ...optimal ]; + + if ( complete.has('all-urls') === false ) { + const matches = [ ...ut.matchesFromHostnames( - ut.subtractHostnameIters( - Array.from(complete), - excludeHostnames - ) - ) - ); + ut.subtractHostnameIters(includedByMode, excludedByFilter) + ), + ...ut.matchesFromHostnames( + ut.intersectHostnameIters(includedByMode, includedByFilter) + ), + ]; + if ( matches.length === 0 ) { return; } + const registered = before.get('css-generic-some'); + before.delete('css-generic-some'); // Important! + const directive = { + id: 'css-generic-some', + js, + allFrames: true, + matches, + runAt: 'document_idle', + }; + if ( registered === undefined ) { // register + context.toAdd.push(directive); + } else if ( // update + ut.strArrayEq(registered.js, js, false) === false || + ut.strArrayEq(registered.matches, directive.matches) === false + ) { + context.toRemove.push('css-generic-some'); + context.toAdd.push(directive); + } + return; } - if ( matches.length === 0 ) { return; } - - const registered = before.get('css-generic'); - before.delete('css-generic'); // Important! - - const directive = { - id: 'css-generic', + const excludeMatches = [ + ...ut.matchesFromHostnames(excludedByMode), + ...ut.matchesFromHostnames(excludedByFilter), + ]; + const registeredAll = before.get('css-generic-all'); + before.delete('css-generic-all'); // Important! + const directiveAll = { + id: 'css-generic-all', js, - matches, - excludeMatches, + allFrames: true, + matches: [ '' ], runAt: 'document_idle', }; - - // register - if ( registered === undefined ) { - context.toAdd.push(directive); - return; + if ( excludeMatches.length !== 0 ) { + directiveAll.excludeMatches = excludeMatches; } - // update - if ( - arrayEq(registered.js, js, false) === false || - arrayEq(registered.matches, matches) === false || - arrayEq(registered.excludeMatches, excludeMatches) === false + if ( registeredAll === undefined ) { // register + context.toAdd.push(directiveAll); + } else if ( // update + ut.strArrayEq(registeredAll.js, js, false) === false || + ut.strArrayEq(registeredAll.excludeMatches, directiveAll.excludeMatches) === false ) { - context.toRemove.push('css-generic'); - context.toAdd.push(directive); - } -} - -/******************************************************************************/ - -function registerProcedural(context) { - const { before, filteringModeDetails, rulesetsDetails } = context; - - const js = []; - for ( const rulesetDetails of rulesetsDetails ) { - const count = rulesetDetails.css?.procedural || 0; - if ( count === 0 ) { continue; } - js.push(`/rulesets/scripting/procedural/${rulesetDetails.id}.js`); + context.toRemove.push('css-generic-all'); + context.toAdd.push(directiveAll); } - if ( js.length === 0 ) { return; } - - const { none, basic, optimal, complete } = filteringModeDetails; const matches = [ - ...ut.matchesFromHostnames(optimal), - ...ut.matchesFromHostnames(complete), + ...ut.matchesFromHostnames( + ut.subtractHostnameIters(includedByFilter, excludedByMode) + ), ]; if ( matches.length === 0 ) { return; } - - js.push('/js/scripting/css-procedural.js'); - - const excludeMatches = []; - if ( none.has('all-urls') === false ) { - excludeMatches.push(...ut.matchesFromHostnames(none)); - } - if ( basic.has('all-urls') === false ) { - excludeMatches.push(...ut.matchesFromHostnames(basic)); - } - - const registered = before.get('css-procedural'); - before.delete('css-procedural'); // Important! - - const directive = { - id: 'css-procedural', + const registeredSome = before.get('css-generic-some'); + before.delete('css-generic-some'); // Important! + const directiveSome = { + id: 'css-generic-some', js, allFrames: true, matches, - excludeMatches, - runAt: 'document_start', + runAt: 'document_idle', }; - - // register - if ( registered === undefined ) { - context.toAdd.push(directive); - return; - } - - // update - if ( - arrayEq(registered.js, js, false) === false || - arrayEq(registered.matches, matches) === false || - arrayEq(registered.excludeMatches, excludeMatches) === false + if ( registeredSome === undefined ) { // register + context.toAdd.push(directiveSome); + } else if ( // update + ut.strArrayEq(registeredSome.js, js, false) === false || + ut.strArrayEq(registeredSome.matches, directiveSome.matches) === false ) { - context.toRemove.push('css-procedural'); - context.toAdd.push(directive); + context.toRemove.push('css-generic-some'); + context.toAdd.push(directiveSome); } } /******************************************************************************/ -function registerDeclarative(context) { +function registerProcedural(context) { const { before, filteringModeDetails, rulesetsDetails } = context; const js = []; for ( const rulesetDetails of rulesetsDetails ) { - const count = rulesetDetails.css?.declarative || 0; + const count = rulesetDetails.css?.procedural || 0; if ( count === 0 ) { continue; } - js.push(`/rulesets/scripting/declarative/${rulesetDetails.id}.js`); + js.push(`/rulesets/scripting/procedural/${rulesetDetails.id}.js`); } if ( js.length === 0 ) { return; } @@ -311,27 +304,35 @@ ]; if ( matches.length === 0 ) { return; } - js.push('/js/scripting/css-declarative.js'); + normalizeMatches(matches); + + js.unshift('/js/scripting/css-api.js', '/js/scripting/isolated-api.js'); + js.push('/js/scripting/css-procedural.js'); const excludeMatches = []; - if ( none.has('all-urls') === false ) { - excludeMatches.push(...ut.matchesFromHostnames(none)); - } - if ( basic.has('all-urls') === false ) { - excludeMatches.push(...ut.matchesFromHostnames(basic)); + if ( none.has('all-urls') === false && basic.has('all-urls') === false ) { + const toExclude = [ + ...ut.matchesFromHostnames(none), + ...ut.matchesFromHostnames(basic), + ]; + for ( const hn of toExclude ) { + excludeMatches.push(hn); + } } - const registered = before.get('css-declarative'); - before.delete('css-declarative'); // Important! + const registered = before.get('css-procedural'); + before.delete('css-procedural'); // Important! const directive = { - id: 'css-declarative', + id: 'css-procedural', js, - allFrames: true, matches, - excludeMatches, + allFrames: true, runAt: 'document_start', }; + if ( excludeMatches.length !== 0 ) { + directive.excludeMatches = excludeMatches; + } // register if ( registered === undefined ) { @@ -341,11 +342,11 @@ // update if ( - arrayEq(registered.js, js, false) === false || - arrayEq(registered.matches, matches) === false || - arrayEq(registered.excludeMatches, excludeMatches) === false + ut.strArrayEq(registered.js, js, false) === false || + ut.strArrayEq(registered.matches, matches) === false || + ut.strArrayEq(registered.excludeMatches, excludeMatches) === false ) { - context.toRemove.push('css-declarative'); + context.toRemove.push('css-procedural'); context.toAdd.push(directive); } } @@ -370,6 +371,9 @@ ]; if ( matches.length === 0 ) { return; } + normalizeMatches(matches); + + js.unshift('/js/scripting/css-api.js', '/js/scripting/isolated-api.js'); js.push('/js/scripting/css-specific.js'); const excludeMatches = []; @@ -386,11 +390,13 @@ const directive = { id: 'css-specific', js, - allFrames: true, matches, - excludeMatches, + allFrames: true, runAt: 'document_start', }; + if ( excludeMatches.length !== 0 ) { + directive.excludeMatches = excludeMatches; + } // register if ( registered === undefined ) { @@ -400,9 +406,9 @@ // update if ( - arrayEq(registered.js, js, false) === false || - arrayEq(registered.matches, matches) === false || - arrayEq(registered.excludeMatches, excludeMatches) === false + ut.strArrayEq(registered.js, js, false) === false || + ut.strArrayEq(registered.matches, matches) === false || + ut.strArrayEq(registered.excludeMatches, excludeMatches) === false ) { context.toRemove.push('css-specific'); context.toAdd.push(directive); @@ -431,7 +437,7 @@ const scriptletList = scriptletDetails.get(rulesetId); if ( scriptletList === undefined ) { continue; } - for ( const [ token, scriptletHostnames ] of scriptletList ) { + for ( const [ token, details ] of scriptletList ) { const id = `${rulesetId}.${token}`; const registered = before.get(id); @@ -440,40 +446,38 @@ let targetHostnames = []; if ( hasBroadHostPermission ) { excludeMatches.push(...permissionRevokedMatches); - if ( scriptletHostnames.length > 100 ) { + if ( details.hostnames.length > 100 ) { targetHostnames = [ '*' ]; } else { - targetHostnames = scriptletHostnames; + targetHostnames = details.hostnames; } } else if ( permissionGrantedHostnames.length !== 0 ) { - if ( scriptletHostnames.includes('*') ) { + if ( details.hostnames.includes('*') ) { targetHostnames = permissionGrantedHostnames; } else { targetHostnames = ut.intersectHostnameIters( - scriptletHostnames, + details.hostnames, permissionGrantedHostnames ); } } if ( targetHostnames.length === 0 ) { continue; } matches.push(...ut.matchesFromHostnames(targetHostnames)); + normalizeMatches(matches); before.delete(id); // Important! const directive = { id, js: [ `/rulesets/scripting/scriptlet/${id}.js` ], - allFrames: true, matches, - excludeMatches, + allFrames: true, + matchOriginAsFallback: true, runAt: 'document_start', + world: details.world, }; - - // https://bugzilla.mozilla.org/show_bug.cgi?id=1736575 - // `MAIN` world not yet supported in Firefox - if ( isGecko === false ) { - directive.world = 'MAIN'; - directive.matchOriginAsFallback = true; + if ( excludeMatches.length !== 0 ) { + directive.excludeMatches = excludeMatches; } // register @@ -484,8 +488,8 @@ // update if ( - arrayEq(registered.matches, matches) === false || - arrayEq(registered.excludeMatches, excludeMatches) === false + ut.strArrayEq(registered.matches, matches) === false || + ut.strArrayEq(registered.excludeMatches, excludeMatches) === false ) { context.toRemove.push(id); context.toAdd.push(directive); @@ -496,11 +500,15 @@ /******************************************************************************/ -async function registerInjectables(origins) { - void origins; +// Issue: Safari appears to completely ignore excludeMatches +// https://github.com/radiolondra/ExcludeMatches-Test +async function registerInjectables() { if ( browser.scripting === undefined ) { return false; } + if ( registerInjectables.barrier ) { return true; } + registerInjectables.barrier = true; + const [ filteringModeDetails, rulesetsDetails, @@ -528,27 +536,40 @@ toRemove, }; - registerDeclarative(context); - registerProcedural(context); - registerScriptlet(context, scriptletDetails); - registerSpecific(context); - registerGeneric(context, genericDetails); - registerHighGeneric(context, genericDetails); + await Promise.all([ + registerProcedural(context), + registerScriptlet(context, scriptletDetails), + registerSpecific(context), + registerGeneric(context, genericDetails), + registerHighGeneric(context, genericDetails), + registerCustomFilters(context), + registerToolbarIconToggler(context), + ]); toRemove.push(...Array.from(before.keys())); if ( toRemove.length !== 0 ) { ubolLog(`Unregistered ${toRemove} content (css/js)`); - await browser.scripting.unregisterContentScripts({ ids: toRemove }) - .catch(reason => { console.info(reason); }); + try { + await browser.scripting.unregisterContentScripts({ ids: toRemove }); + localRemove('$scripting.unregisterContentScripts'); + } catch(reason) { + ubolErr(`unregisterContentScripts/${reason}`); + } } if ( toAdd.length !== 0 ) { ubolLog(`Registered ${toAdd.map(v => v.id)} content (css/js)`); - await browser.scripting.registerContentScripts(toAdd) - .catch(reason => { console.info(reason); }); + try { + await browser.scripting.registerContentScripts(toAdd); + localRemove('$scripting.registerContentScripts'); + } catch(reason) { + ubolErr(`registerContentScripts/${reason}`); + } } + registerInjectables.barrier = false; + return true; } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/settings.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/settings.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/settings.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/settings.js 2025-10-25 19:32:51.000000000 +0000 @@ -21,7 +21,7 @@ import { browser, sendMessage } from './ext.js'; import { dom, qs$ } from './dom.js'; -import punycode from './punycode.js'; +import { hashFromIterable } from './dashboard.js'; import { renderFilterLists } from './filter-lists.js'; /******************************************************************************/ @@ -30,12 +30,6 @@ /******************************************************************************/ -function hashFromIterable(iter) { - return Array.from(iter).sort().join('\n'); -} - -/******************************************************************************/ - function renderAdminRules() { const { disabledFeatures: forbid = [] } = cachedRulesetData; if ( forbid.length === 0 ) { return; } @@ -53,7 +47,6 @@ } renderDefaultMode(); - renderTrustedSites(); qs$('#autoReload input[type="checkbox"]').checked = cachedRulesetData.autoReload; @@ -69,18 +62,16 @@ { const input = qs$('#strictBlockMode input[type="checkbox"]'); - const canStrictBlock = cachedRulesetData.defaultFilteringMode > 1; + const canStrictBlock = cachedRulesetData.hasOmnipotence; input.checked = canStrictBlock && cachedRulesetData.strictBlockMode; dom.attr(input, 'disabled', canStrictBlock ? null : ''); } { - dom.prop('#developerMode input[type="checkbox"]', 'checked', - Boolean(cachedRulesetData.developerMode) - ); - if ( cachedRulesetData.isSideloaded ) { - dom.attr('#developerMode', 'hidden', null); - } + const state = Boolean(cachedRulesetData.developerMode) && + cachedRulesetData.disabledFeatures?.includes('develop') !== true; + dom.body.dataset.develop = `${state}`; + dom.prop('#developerMode input[type="checkbox"]', 'checked', state); } } @@ -102,17 +93,18 @@ const newLevel = parseInt(input.value, 10); switch ( newLevel ) { - case 1: { // Revoke broad permissions - await browser.permissions.remove({ - origins: [ '' ] + case 1: { + const actualLevel = await sendMessage({ + what: 'setDefaultFilteringMode', + level: newLevel, }); - cachedRulesetData.defaultFilteringMode = 1; + cachedRulesetData.defaultFilteringMode = actualLevel; break; } case 2: - case 3: { // Request broad permissions + case 3: { const granted = await browser.permissions.request({ - origins: [ '' ] + origins: [ '' ], }); if ( granted ) { const actualLevel = await sendMessage({ @@ -120,6 +112,7 @@ level: newLevel, }); cachedRulesetData.defaultFilteringMode = actualLevel; + cachedRulesetData.hasOmnipotence = true; } break; } @@ -139,6 +132,49 @@ /******************************************************************************/ +async function backupSettings() { + const api = await import('./backup-restore.js'); + const data = await api.backupToObject(cachedRulesetData); + if ( data instanceof Object === false ) { return; } + const json = JSON.stringify(data, null, 2) + '\n'; + const a = document.createElement('a'); + a.href = `data:text/plain;charset=utf-8,${encodeURIComponent(json)}`; + dom.attr(a, 'download', 'my-ubol-settings.json'); + dom.attr(a, 'type', 'application/json'); + a.click(); +} + +async function restoreSettings() { + const input = qs$('section[data-pane="settings"] input[type="file"]'); + input.onchange = ev => { + input.onchange = null; + const file = ev.target.files[0]; + if ( file === undefined || file.name === '' ) { return; } + const fr = new FileReader(); + fr.onload = ( ) => { + fr.onload = null; + if ( typeof fr.result !== 'string' ) { return; } + let data; + try { + data = JSON.parse(fr.result); + } catch { + } + if ( data instanceof Object === false ) { return; } + import('./backup-restore.js').then(api => { + api.restoreFromObject(data); + }); + }; + fr.readAsText(file); + }; + // Reset to empty string, this will ensure a change event is properly + // triggered if the user pick a file, even if it's the same as the last + // one picked. + input.value = ''; + input.click(); +} + +/******************************************************************************/ + dom.on('#autoReload input[type="checkbox"]', 'change', ev => { sendMessage({ what: 'setAutoReload', @@ -161,49 +197,18 @@ }); dom.on('#developerMode input[type="checkbox"]', 'change', ev => { - sendMessage({ - what: 'setDeveloperMode', - state: ev.target.checked, - }); + const state = ev.target.checked; + sendMessage({ what: 'setDeveloperMode', state }); + dom.body.dataset.develop = `${state}`; }); -/******************************************************************************/ - -function renderTrustedSites() { - const textarea = qs$('#trustedSites'); - const hostnames = cachedRulesetData.trustedSites || []; - textarea.value = hostnames.map(hn => punycode.toUnicode(hn)).join('\n'); - if ( textarea.value !== '' ) { - textarea.value += '\n'; - } -} - -function changeTrustedSites() { - const hostnames = getStagedTrustedSites(); - const hash = hashFromIterable(cachedRulesetData.trustedSites || []); - if ( hashFromIterable(hostnames) === hash ) { return; } - sendMessage({ - what: 'setTrustedSites', - hostnames, - }); -} - -function getStagedTrustedSites() { - const textarea = qs$('#trustedSites'); - return textarea.value.split(/\s/).map(hn => { - try { - return punycode.toASCII( - (new URL(`https://${hn}/`)).hostname - ); - } catch(_) { - } - return ''; - }).filter(hn => hn !== ''); -} - -dom.on('#trustedSites', 'blur', changeTrustedSites); +dom.on('section[data-pane="settings"] [data-i18n="backupButton"]', 'click', ( ) => { + backupSettings(); +}); -self.addEventListener('beforeunload', changeTrustedSites); +dom.on('section[data-pane="settings"] [data-i18n="restoreButton"]', 'click', ( ) => { + restoreSettings(); +}); /******************************************************************************/ @@ -218,17 +223,9 @@ const local = cachedRulesetData; let render = false; - // Keep added sites which have not yet been committed - if ( message.trustedSites !== undefined ) { - if ( hashFromIterable(message.trustedSites) !== hashFromIterable(local.trustedSites) ) { - const current = new Set(local.trustedSites); - const staged = new Set(getStagedTrustedSites()); - for ( const hn of staged ) { - if ( current.has(hn) === false ) { continue; } - staged.delete(hn); - } - const combined = Array.from(new Set([ ...message.trustedSites, ...staged ])); - local.trustedSites = combined; + if ( message.hasOmnipotence !== undefined ) { + if ( message.hasOmnipotence !== local.hasOmnipotence ) { + local.hasOmnipotence = message.hasOmnipotence; render = true; } } @@ -261,6 +258,13 @@ } } + if ( message.developerMode !== undefined ) { + if ( message.developerMode !== local.developerMode ) { + local.developerMode = message.developerMode; + render = true; + } + } + if ( message.adminRulesets !== undefined ) { if ( hashFromIterable(message.adminRulesets) !== hashFromIterable(local.adminRulesets) ) { local.adminRulesets = message.adminRulesets; @@ -269,10 +273,8 @@ } if ( message.enabledRulesets !== undefined ) { - if ( hashFromIterable(message.enabledRulesets) !== hashFromIterable(local.enabledRulesets) ) { - local.enabledRulesets = message.enabledRulesets; - render = true; - } + local.enabledRulesets = message.enabledRulesets; + render = true; } if ( render === false ) { return; } @@ -291,12 +293,14 @@ renderAdminRules(); renderFilterLists(cachedRulesetData); renderWidgets(); + } catch(reason) { + console.error(reason); + } finally { dom.cl.remove(dom.body, 'loading'); - } catch(ex) { } listen(); }).catch(reason => { - console.trace(reason); + console.error(reason); }); /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/strictblock.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/strictblock.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/strictblock.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/strictblock.js 2025-10-25 19:32:51.000000000 +0000 @@ -42,7 +42,7 @@ b.append(hn); fragment.append(raw.slice(0,i), b, raw.slice(i+hn.length)); return fragment; - } catch(_) { + } catch { } return raw; } @@ -55,7 +55,7 @@ try { toURL.href = self.location.hash.slice(1); toFinalURL.href = toURL.href; -} catch(_) { +} catch { } dom.clear('#theURL > p > span:first-of-type'); @@ -144,7 +144,7 @@ let url; try { url = new URL(rawURL); - } catch(ex) { + } catch { return false; } @@ -243,7 +243,7 @@ const urlskipLists = await Promise.all(toFetch); const toHn = toURL.hostname; const matchesHn = hn => { - if ( hn.endsWith(toHn) === false ) { return false; } + if ( toHn.endsWith(hn) === false ) { return false; } if ( hn.length === toHn.length ) { return true; } return toHn.charAt(toHn.length - hn.length - 1) === '.'; }; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/theme.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/theme.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/theme.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/theme.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,17 +19,22 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - import { dom } from './dom.js'; /******************************************************************************/ -const mql = self.matchMedia('(prefers-color-scheme: dark)'); -const theme = mql instanceof Object && mql.matches === true - ? 'dark' - : 'light'; -dom.cl.toggle(dom.html, 'dark', theme === 'dark'); -dom.cl.toggle(dom.html, 'light', theme !== 'dark'); +{ + const mql = self.matchMedia('(prefers-color-scheme: dark)'); + const theme = mql instanceof Object && mql.matches === true + ? 'dark' + : 'light'; + dom.cl.toggle(dom.html, 'dark', theme === 'dark'); + dom.cl.toggle(dom.html, 'light', theme !== 'dark'); +} + +{ + const mql = self.matchMedia('(hover: hover)'); + const isTouchScreen = mql.matches !== true; + dom.cl.toggle(dom.html, 'mobile', isTouchScreen); + dom.cl.toggle(dom.html, 'desktop', isTouchScreen === false); +} diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/tool-overlay-ui.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/tool-overlay-ui.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/tool-overlay-ui.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/tool-overlay-ui.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,237 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { dom, qs$ } from './dom.js'; +import { sendMessage } from './ext.js'; + +/******************************************************************************/ + +export const toolOverlay = { + url: new URL('about:blank'), + svgRoot: qs$('svg#overlay'), + svgOcean: qs$('svg#overlay > path'), + svgIslands: qs$('svg#overlay > path + path'), + emptyPath: 'M0 0', + port: null, + + start(onmessage) { + this.onmessage = onmessage; + globalThis.addEventListener('message', ev => { + const msg = ev.data || {}; + if ( msg.what !== 'startOverlay' ) { return; } + if ( Array.isArray(ev.ports) === false ) { return; } + if ( ev.ports.length === 0 ) { return; } + toolOverlay.port = ev.ports[0]; + toolOverlay.port.onmessage = ev => { + this.onMessage(ev.data || {}); + }; + toolOverlay.port.onmessageerror = ( ) => { + this.onmessage({ what: 'stopTool' }); + }; + this.moveable = qs$('aside:has(#move)'); + if ( this.moveable !== null ) { + dom.on('aside #move', 'pointerdown', ev => { this.mover(ev); }); + dom.on('aside #move', 'touchstart', this.eatTouchEvent); + } + this.onMessage({ what: 'startTool', + url: msg.url, + width: msg.width, + height: msg.height, + }); + dom.cl.remove(dom.body, 'loading'); + }, { once: true }); + }, + + stop() { + this.highlightElementUnderMouse(false); + if ( this.port ) { + this.port.postMessage({ what: 'quitTool' }); + this.port.onmessage = null; + this.port.onmessageerror = null; + this.port = null; + } + }, + + onMessage(wrapped) { + // Response to frame-initiated message? + if ( typeof wrapped?.fromFrameId === 'number' ) { + const resolve = this.pendingMessages.get(wrapped.fromFrameId); + if ( resolve ) { + this.pendingMessages.delete(wrapped.fromFrameId); + resolve(wrapped.msg); + } + return; + } + const msg = wrapped.msg || wrapped; + switch ( msg.what ) { + case 'startTool': { + this.url.href = msg.url; + const ow = msg.width; + const oh = msg.height; + this.svgOcean.setAttribute('d', `M0 0h${ow}v${oh}h-${ow}z`); + break; + } + case 'svgPaths': + this.svgOcean.setAttribute('d', msg.ocean + msg.islands); + this.svgIslands.setAttribute('d', msg.islands || this.emptyPath); + break; + default: + break; + } + const response = this.onmessage && this.onmessage(msg) || undefined; + // Send response if this is script-initiated message + if ( wrapped?.fromScriptId && this.port ) { + const { fromScriptId } = wrapped; + if ( response instanceof Promise ) { + response.then(response => { + if ( this.port === null ) { return; } + this.port.postMessage({ fromScriptId, msg: response }); + }); + } else { + this.port.postMessage({ fromScriptId, msg: response }); + } + } + }, + postMessage(msg) { + if ( this.port === null ) { return; } + const wrapped = { + fromFrameId: this.messageId++, + msg, + }; + return new Promise(resolve => { + this.pendingMessages.set(wrapped.fromFrameId, resolve); + this.port.postMessage(wrapped); + }); + }, + messageId: 1, + pendingMessages: new Map(), + + sendMessage(msg) { + return sendMessage(msg); + }, + + highlightElementUnderMouse(state) { + if ( dom.cl.has(dom.root, 'mobile') ) { return; } + if ( state === this.mstrackerOn ) { return; } + this.mstrackerOn = state; + if ( this.mstrackerOn ) { + dom.on(document, 'mousemove', this.onHover, { passive: true }); + return; + } + dom.off(document, 'mousemove', this.onHover, { passive: true }); + if ( this.mstrackerTimer === undefined ) { return; } + self.cancelAnimationFrame(this.mstrackerTimer); + this.mstrackerTimer = undefined; + }, + onTimer() { + toolOverlay.mstrackerTimer = undefined; + if ( toolOverlay.port === null ) { return; } + toolOverlay.port.postMessage({ + what: 'highlightElementAtPoint', + mx: toolOverlay.mstrackerX, + my: toolOverlay.mstrackerY, + }); + }, + onHover(ev) { + toolOverlay.mstrackerX = ev.clientX; + toolOverlay.mstrackerY = ev.clientY; + if ( toolOverlay.mstrackerTimer !== undefined ) { return; } + toolOverlay.mstrackerTimer = + self.requestAnimationFrame(toolOverlay.onTimer); + }, + mstrackerOn: false, + mstrackerX: 0, mstrackerY: 0, + mstrackerTimer: undefined, + + mover(ev) { + const target = ev.target; + if ( target.matches('#move') === false ) { return; } + if ( dom.cl.has(this.moveable, 'moving') ) { return; } + target.setPointerCapture(ev.pointerId); + this.moverX0 = ev.pageX; + this.moverY0 = ev.pageY; + const rect = this.moveable.getBoundingClientRect(); + this.moverCX0 = rect.x + rect.width / 2; + this.moverCY0 = rect.y + rect.height / 2; + dom.cl.add(this.moveable, 'moving'); + self.addEventListener('pointermove', this.moverMoveAsync, { + passive: true, + capture: true, + }); + self.addEventListener('pointerup', this.moverStop, { capture: true, once: true }); + ev.stopPropagation(); + ev.preventDefault(); + }, + moverMove() { + this.moverTimer = undefined; + const cx1 = this.moverCX0 + this.moverX1 - this.moverX0; + const cy1 = this.moverCY0 + this.moverY1 - this.moverY0; + const rootW = dom.root.clientWidth; + const rootH = dom.root.clientHeight; + const moveableW = this.moveable.clientWidth; + const moveableH = this.moveable.clientHeight; + if ( cx1 < rootW / 2 ) { + this.moveable.style.setProperty('left', `${Math.max(cx1-moveableW/2,2)}px`); + this.moveable.style.removeProperty('right'); + } else { + this.moveable.style.removeProperty('left'); + this.moveable.style.setProperty('right', `${Math.max(rootW-cx1-moveableW/2,2)}px`); + } + if ( cy1 < rootH / 2 ) { + this.moveable.style.setProperty('top', `${Math.max(cy1-moveableH/2,2)}px`); + this.moveable.style.removeProperty('bottom'); + } else { + this.moveable.style.removeProperty('top'); + this.moveable.style.setProperty('bottom', `${Math.max(rootH-cy1-moveableH/2,2)}px`); + } + }, + moverMoveAsync(ev) { + toolOverlay.moverX1 = ev.pageX; + toolOverlay.moverY1 = ev.pageY; + if ( toolOverlay.moverTimer !== undefined ) { return; } + toolOverlay.moverTimer = self.requestAnimationFrame(( ) => { + toolOverlay.moverMove(); + }); + }, + moverStop(ev) { + if ( dom.cl.has(toolOverlay.moveable, 'moving') === false ) { return; } + dom.cl.remove(toolOverlay.moveable, 'moving'); + self.removeEventListener('pointermove', toolOverlay.moverMoveAsync, { + passive: true, + capture: true, + }); + ev.target.releasePointerCapture(ev.pointerId); + ev.stopPropagation(); + ev.preventDefault(); + }, + eatTouchEvent(ev) { + if ( ev.target !== qs$('aside #move') ) { return; } + ev.stopPropagation(); + ev.preventDefault(); + }, + moveable: null, + moverX0: 0, moverY0: 0, + moverX1: 0, moverY1: 0, + moverCX0: 0, moverCY0: 0, + moverTimer: undefined, +}; + +/******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/troubleshooting.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/troubleshooting.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/troubleshooting.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/troubleshooting.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,130 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2024-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { runtime, sendMessage } from './ext.js'; + +/******************************************************************************/ + +function renderData(data, depth = 0) { + const indent = ' '.repeat(depth); + if ( Array.isArray(data) ) { + const out = []; + for ( const value of data ) { + out.push(renderData(value, depth)); + } + return out.join('\n'); + } + if ( typeof data !== 'object' || data === null ) { + return `${indent}${data}`; + } + const out = []; + for ( const [ name, value ] of Object.entries(data) ) { + if ( typeof value === 'object' && value !== null ) { + out.push(`${indent}${name}:`); + out.push(renderData(value, depth + 1)); + continue; + } + out.push(`${indent}${name}: ${value}`); + } + return out.join('\n'); +} + +/******************************************************************************/ + +export async function getTroubleshootingInfo(siteMode) { + const manifest = runtime.getManifest(); + const [ + platformInfo, + defaultConfig, + enabledRulesets, + defaultMode, + userRules, + consoleOutput, + hasOmnipotence, + ] = await Promise.all([ + runtime.getPlatformInfo(), + sendMessage({ what: 'getDefaultConfig' }), + sendMessage({ what: 'getEnabledRulesets' }), + sendMessage({ what: 'getDefaultFilteringMode' }), + sendMessage({ what: 'getEffectiveUserRules' }), + sendMessage({ what: 'getConsoleOutput' }), + sendMessage({ what: 'hasBroadHostPermissions' }), + ]); + const browser = (( ) => { + const extURL = runtime.getURL(''); + let agent = '', version = '?'; + if ( extURL.startsWith('moz-extension:') ) { + agent = 'Firefox'; + const match = /\bFirefox\/(\d+\.\d+)\b/.exec(navigator.userAgent); + version = match && match[1] || '?'; + } else if ( extURL.startsWith('safari-web-extension:') ) { + agent = 'Safari'; + const match = /\bVersion\/(\d+\.\d+)\b/.exec(navigator.userAgent); + version = match && match[1] || '?'; + } else if ( /\bEdg\/\b/.test(navigator.userAgent) ) { + agent = 'Edge'; + const match = /\bEdg\/(\d+)\b/.exec(navigator.userAgent); + version = match && match[1] || '?'; + } else { + agent = 'Chrome'; + const match = /\bChrome\/(\d+)\b/.exec(navigator.userAgent); + version = match && match[1] || '?'; + } + if ( /\bMobile\b/.test(navigator.userAgent) ) { + agent += ' Mobile'; + } + agent += ` ${version} (${platformInfo.os})` + return agent; + })(); + const modes = [ 'no filtering', 'basic', 'optimal', 'complete' ]; + const filtering = {}; + if ( siteMode ) { + filtering.site = `${modes[siteMode]}` + } + filtering.default = `${modes[defaultMode]}`; + const config = { + name: manifest.name, + version: manifest.version, + browser, + filtering, + permission: hasOmnipotence ? 'all' : 'ask', + }; + if ( userRules.length !== 0 ) { + config['user rules'] = userRules.length; + } + const defaultRulesets = defaultConfig.rulesets; + for ( let i = 0; i < enabledRulesets.length; i++ ) { + const id = enabledRulesets[i]; + if ( defaultRulesets.includes(id) ) { continue; } + enabledRulesets[i] = `+${id}`; + } + for ( const id of defaultRulesets ) { + if ( enabledRulesets.includes(id) ) { continue; } + enabledRulesets.push(`-${id}`); + } + config.rulesets = enabledRulesets.sort(); + if ( consoleOutput.length !== 0 ) { + config.console = siteMode + ? consoleOutput.slice(-8) + : consoleOutput; + } + return renderData(config); +} diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/ubo-parser.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/ubo-parser.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/ubo-parser.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/ubo-parser.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,581 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2014-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import * as sfp from './static-filtering-parser.js'; +import punycode from './punycode.js'; +import redirectResourceMap from './redirect-resources.js'; + +/******************************************************************************/ + +const validResourceTypes = [ + 'main_frame', + 'sub_frame', + 'stylesheet', + 'script', + 'image', + 'font', + 'object', + 'xmlhttprequest', + 'ping', + 'csp_report', + 'media', + 'websocket', + 'webtransport', + 'webbundle', + 'other', +]; + +/******************************************************************************/ + +const validRedirectResources = (( ) => { + const out = new Map(); + for ( const [ name, resource ] of redirectResourceMap ) { + out.set(name, name); + if ( resource.alias === undefined ) { continue; } + if ( typeof resource.alias === 'string' ) { + out.set(resource.alias, name); + continue; + } + if ( Array.isArray(resource.alias) ) { + for ( const alias of resource.alias ) { + out.set(alias, name); + } + } + } + return out; +})(); + +const isNotEntity = hn => hn.endsWith('.*') === false; + +/******************************************************************************/ + +function toSuperDomain(hn) { + const pos = hn.indexOf('.'); + if ( pos === -1 ) { return; } + return hn.slice(pos+1); +} + +/******************************************************************************/ + +function parseHostnameList(iter) { + const out = { + included: { + good: [], + bad: [], + }, + excluded: { + good: [], + bad: [], + }, + }; + for ( let { hn, not, bad } of iter ) { + bad ||= hn.includes('/') || hn.includes('*'); + const hnAscii = bad === false && hn.startsWith('xn--') + ? punycode.toASCII(hn) + : hn; + const destination = not ? out.excluded : out.included; + if ( bad ) { + destination.bad.push(hnAscii); + } else { + destination.good.push(hnAscii); + } + } + return out; +} + +/******************************************************************************/ + +function ownerFromPropertyPath(root, path) { + let owner = root; + let prop = path; + for (;;) { + if ( owner instanceof Object === false ) { break; } + const pos = prop.indexOf('.'); + if ( pos === -1 ) { break; } + owner = owner[prop.slice(0, pos)]; + prop = prop.slice(pos+1) + } + return { owner: owner ?? undefined, prop }; +} + +/******************************************************************************/ + +function mergeArrays(rules, propertyPath) { + const out = []; + const distinctRules = new Map(); + for ( const rule of rules ) { + const { id } = rule; + const { owner, prop } = ownerFromPropertyPath(rule, propertyPath); + if ( owner === undefined || Array.isArray(owner[prop]) === false ) { + out.push(rule); + continue; + } + const collection = owner[prop] || []; + owner[prop] = undefined; + rule.id = undefined; + const hash = JSON.stringify(rule); + const details = distinctRules.get(hash) || + { id, collection: new Set() }; + if ( details.collection.size === 0 ) { + distinctRules.set(hash, details); + } + for ( const hn of collection ) { + details.collection.add(hn); + } + } + for ( const [ hash, { id, collection } ] of distinctRules ) { + const rule = JSON.parse(hash); + if ( id ) { + rule.id = id; + } + if ( collection.size !== 0 ) { + const { owner, prop } = ownerFromPropertyPath(rule, propertyPath); + owner[prop] = Array.from(collection).sort(); + } + out.push(rule); + } + return out; +} + +/******************************************************************************/ + +function minimizeRuleset(rules) { + rules = mergeArrays(rules, 'condition.requestDomains'); + rules = mergeArrays(rules, 'condition.excludedRequestDomains'); + rules = mergeArrays(rules, 'condition.initiatorDomains'); + rules = mergeArrays(rules, 'condition.excludedInitiatorDomains'); + rules = mergeArrays(rules, 'condition.resourceTypes'); + rules = mergeArrays(rules, 'condition.excludedRequestMethods'); + rules = mergeArrays(rules, 'condition.requestMethods'); + rules = mergeArrays(rules, 'condition.excludedResourceTypes'); + rules = mergeArrays(rules, 'action.redirect.transform.queryTransform.removeParams'); + return rules; +} + +/******************************************************************************/ + +function minimizeRules(rules) { + const hostnameListProp = [ + 'requestDomains', + 'excludedRequestDomains', + 'initiatorDomains', + 'excludedInitiatorDomains', + ]; + for ( const rule of rules ) { + for ( const prop of hostnameListProp ) { + const hostnames = rule.condition[prop]; + if ( hostnames === undefined ) { continue; } + if ( hostnames.length === 1 ) { continue; } + const hnSet = new Set(hostnames); + for ( let hn of hnSet ) { + for (;;) { + const hnup = toSuperDomain(hn); + if ( hnup === undefined ) { break; } + if ( hnSet.has(hnup) ) { hnSet.delete(hn); } + hn = hnup; + } + } + if ( hnSet.size === hostnames.length ) { continue; } + rule.condition[prop] = Array.from(hnSet).sort(); + } + } + return rules; +} + +/******************************************************************************/ + +function dropEntities(rule, prop) { + const { condition } = rule; + if ( condition[prop] === undefined ) { return; } + const sanitized = condition[prop].filter(a => isNotEntity(a)); + if ( sanitized.length === condition[prop].length ) { return; } + if ( sanitized.length === 0 ) { return 0; } + condition.requestDomains = sanitized; +} + +/******************************************************************************/ + +function validateRules(rules) { + const out = []; + for ( const rule of rules ) { + const { condition } = rule; + // "Only one of resourceTypes and excludedResourceTypes should be specified" + if ( condition.resourceTypes ) { + if ( condition.excludedResourceTypes ) { continue; } + } + // "Only one of requestMethods and excludedRequestMethods should be specified" + if ( condition.requestMethods ) { + if ( condition.excludedRequestMethods ) { continue; } + } + // Drop entity-based hostnames + if ( dropEntities(rule, 'requestDomains') === 0 ) { continue; } + if ( dropEntities(rule, 'excludedRequestDomains') === 0 ) { continue; } + if ( dropEntities(rule, 'initiatorDomains') === 0 ) { continue; } + if ( dropEntities(rule, 'excludedInitiatorDomains') === 0 ) { continue; } + // regexSubstitution requires regexFilter + if ( rule.action?.redirect?.regexSubstitution ) { + if ( rule.condition.regexFilter === undefined ) { continue; } + } + out.push(rule); + } + return out; +} + +/******************************************************************************/ + +export function parseNetworkFilter(parser) { + if ( parser.isNetworkFilter() === false ) { return; } + if ( parser.hasError() ) { return; } + + const rule = { + action: { type: 'block' }, + condition: { }, + }; + if ( parser.isException() ) { + rule.action.type = 'allow'; + } + + let pattern = parser.getNetPattern(); + if ( parser.isHostnamePattern() ) { + rule.condition.requestDomains = [ pattern ]; + } else if ( parser.isPlainPattern() || parser.isGenericPattern() ) { + if ( parser.isLeftHnAnchored() ) { + pattern = `||${pattern}`; + } else if ( parser.isLeftAnchored() ) { + pattern = `|${pattern}`; + } + if ( parser.isRightAnchored() ) { + pattern = `${pattern}|`; + } + rule.condition.urlFilter = pattern; + } else if ( parser.isRegexPattern() ) { + rule.condition.regexFilter = pattern; + } else if ( parser.isAnyPattern() === false ) { + rule.condition.urlFilter = pattern; + } + + const defaultResourceTypes = new Set(); + let defaultUrlFilter = ''; + + const initiatorDomains = new Set(); + const excludedInitiatorDomains = new Set(); + const requestDomains = new Set(); + const excludedRequestDomains = new Set(); + const requestMethods = new Set(); + const excludedRequestMethods = new Set(); + const resourceTypes = new Set(); + const excludedResourceTypes = new Set(); + + const processResourceType = (resourceType, nodeType) => { + const not = parser.isNegatedOption(nodeType) + if ( validResourceTypes.includes(resourceType) === false ) { + if ( not ) { return; } + } + if ( not ) { + excludedResourceTypes.add(resourceType); + } else { + resourceTypes.add(resourceType); + } + }; + + let priority = 0; + + for ( const type of parser.getNodeTypes() ) { + switch ( type ) { + case sfp.NODE_TYPE_NET_OPTION_NAME_1P: + rule.condition.domainType = parser.isNegatedOption(type) + ? 'thirdParty' + : 'firstParty'; + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_STRICT1P: + case sfp.NODE_TYPE_NET_OPTION_NAME_STRICT3P: + case sfp.NODE_TYPE_NET_OPTION_NAME_BADFILTER: + case sfp.NODE_TYPE_NET_OPTION_NAME_CNAME: + case sfp.NODE_TYPE_NET_OPTION_NAME_EHIDE: + case sfp.NODE_TYPE_NET_OPTION_NAME_GENERICBLOCK: + case sfp.NODE_TYPE_NET_OPTION_NAME_GHIDE: + case sfp.NODE_TYPE_NET_OPTION_NAME_IPADDRESS: + case sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE: + case sfp.NODE_TYPE_NET_OPTION_NAME_REPLACE: + case sfp.NODE_TYPE_NET_OPTION_NAME_SHIDE: + case sfp.NODE_TYPE_NET_OPTION_NAME_URLSKIP: + return; + case sfp.NODE_TYPE_NET_OPTION_NAME_INLINEFONT: + case sfp.NODE_TYPE_NET_OPTION_NAME_INLINESCRIPT: + case sfp.NODE_TYPE_NET_OPTION_NAME_POPUNDER: + case sfp.NODE_TYPE_NET_OPTION_NAME_POPUP: + case sfp.NODE_TYPE_NET_OPTION_NAME_WEBRTC: + processResourceType('', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_3P: + rule.condition.domainType = parser.isNegatedOption(type) + ? 'firstParty' + : 'thirdParty'; + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_ALL: + validResourceTypes.forEach(a => resourceTypes.add(a)); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_CSP: + if ( rule.action.responseHeaders ) { return; } + rule.action.type = 'modifyHeaders'; + rule.action.responseHeaders = [ { + header: 'content-security-policy', + operation: 'append', + value: parser.getNetOptionValue(type), + } ]; + defaultResourceTypes.add('main_frame'); + defaultResourceTypes.add('sub_frame'); + defaultResourceTypes.add('object'); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_CSS: + processResourceType('stylesheet', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_DENYALLOW: { + const { included, excluded } = parseHostnameList( + parser.getNetFilterDenyallowOptionIterator() + ); + if ( excluded.good.length !== 0 || excluded.bad.length !== 0 ) { return; } + if ( included.bad.length !== 0 ) { return; } + if ( included.good.length === 0 ) { return; } + for ( const hn of included.good ) { + excludedRequestDomains.add(hn); + } + break; + } + case sfp.NODE_TYPE_NET_OPTION_NAME_DOC: + processResourceType('main_frame', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_FONT: + processResourceType('font', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_FRAME: + processResourceType('sub_frame', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_FROM: { + const { included, excluded } = parseHostnameList( + parser.getNetFilterFromOptionIterator() + ); + if ( included.good.length === 0 ) { + if ( included.bad.length !== 0 ) { return; } + } + if ( excluded.bad.length !== 0 ) { return; } + for ( const hn of included.good ) { + initiatorDomains.add(hn); + } + for ( const hn of excluded.good ) { + excludedInitiatorDomains.add(hn); + } + break; + } + case sfp.NODE_TYPE_NET_OPTION_NAME_HEADER: { + const details = sfp.parseHeaderValue(parser.getNetOptionValue(type)); + const headerInfo = { + header: details.name, + }; + if ( details.value !== '' ) { + if ( details.isRegex ) { return; } + headerInfo.values = [ details.value ]; + } + rule.condition.responseHeaders = [ headerInfo ]; + break; + } + case sfp.NODE_TYPE_NET_OPTION_NAME_IMAGE: + processResourceType('image', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_IMPORTANT: + priority += 30; + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_MATCHCASE: + rule.condition.isUrlFilterCaseSensitive = true; + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_MEDIA: + processResourceType('media', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_METHOD: { + const value = parser.getNetOptionValue(type); + for ( const method of value.toLowerCase().split('|') ) { + const not = method.charCodeAt(0) === 0x7E /* '~' */; + if ( not ) { + excludedRequestMethods.add(method.slice(1)); + } else { + requestMethods.add(method); + } + } + break; + } + case sfp.NODE_TYPE_NET_OPTION_NAME_OBJECT: + processResourceType('object', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_OTHER: + processResourceType('other', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_PERMISSIONS: + if ( rule.action.responseHeaders ) { return; } + rule.action.type = 'modifyHeaders'; + rule.action.responseHeaders = [ { + header: 'permissions-policy', + operation: 'append', + value: parser.getNetOptionValue(type), + } ]; + defaultResourceTypes.add('main_frame'); + defaultResourceTypes.add('sub_frame'); + defaultResourceTypes.add('object'); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_PING: + processResourceType('ping', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_REASON: + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECT: { + if ( rule.action.type !== 'block' ) { return; } + let value = parser.getNetOptionValue(type); + const match = /:(\d+)$/.exec(value); + if ( match ) { + const subpriority = parseInt(match[1], 10); + priority += Math.min(subpriority, 8); + value = value.slice(0, match.index); + } + if ( validRedirectResources.has(value) === false ) { return; } + rule.action.type = 'redirect'; + rule.action.redirect = { + extensionPath: `/web_accessible_resources/${validRedirectResources.get(value)}`, + }; + priority += 11; + break; + } + case sfp.NODE_TYPE_NET_OPTION_NAME_REMOVEPARAM: { + const details = sfp.parseQueryPruneValue(parser.getNetOptionValue(type)); + if ( details.bad ) { return; } + if ( details.not ) { return; } + if ( details.re ) { return; } + const removeParams = []; + if ( details.name ) { + removeParams.push(details.name); + } + rule.action.type = 'redirect'; + rule.action.redirect = { + transform: { queryTransform: { removeParams } } + }; + defaultResourceTypes.add('main_frame'); + defaultResourceTypes.add('sub_frame'); + defaultResourceTypes.add('xmlhttprequest'); + defaultUrlFilter = '?'; + break; + } + case sfp.NODE_TYPE_NET_OPTION_NAME_SCRIPT: + processResourceType('script', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_TO: { + const { included, excluded } = parseHostnameList( + parser.getNetFilterToOptionIterator() + ); + if ( included.good.length === 0 ) { + if ( included.bad.length !== 0 ) { return; } + } + if ( excluded.bad.length !== 0 ) { return; } + for ( const hn of included.good ) { + requestDomains.add(hn); + } + for ( const hn of excluded.good ) { + excludedRequestDomains.add(hn); + } + break; + } + case sfp.NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM: { + const parsed = sfp.parseReplaceByRegexValue(parser.getNetOptionValue(type)); + if ( parsed === undefined ) { return; } + if ( parsed.re ) { return; } + rule.action.type = 'redirect'; + rule.action.redirect = { + regexSubstitution: parsed.replacement.replace(/\$(\d+)/g, '\\$1'), + }; + break; + } + case sfp.NODE_TYPE_NET_OPTION_NAME_XHR: + processResourceType('xmlhttprequest', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_WEBSOCKET: + processResourceType('websocket', type); + break; + default: + break; + } + } + if ( pattern === '*' && defaultUrlFilter !== '' ) { + rule.condition.urlFilter = defaultUrlFilter; + } + if ( initiatorDomains.size !== 0 ) { + rule.condition.initiatorDomains = Array.from(initiatorDomains).sort(); + } + if ( excludedInitiatorDomains.size !== 0 ) { + rule.condition.excludedInitiatorDomains = Array.from(excludedInitiatorDomains).sort(); + } + if ( requestDomains.size !== 0 ) { + rule.condition.requestDomains = Array.from(requestDomains).sort(); + } + if ( excludedRequestDomains.size !== 0 ) { + rule.condition.excludedRequestDomains = Array.from(excludedRequestDomains).sort(); + } + if ( requestMethods.size !== 0 ) { + rule.condition.requestMethods = Array.from(requestMethods).sort(); + } + if ( excludedRequestMethods.size !== 0 ) { + rule.condition.excludedRequestMethods = Array.from(excludedRequestMethods).sort(); + } + if ( resourceTypes.size === 0 && excludedResourceTypes.size === 0 ) { + defaultResourceTypes.forEach(a => resourceTypes.add(a)); + } + if ( resourceTypes.size !== 0 ) { + const types = Array.from(resourceTypes).filter(a => a !== '').sort(); + if ( types.length === 0 ) { return; } + rule.condition.resourceTypes = types; + } + if ( excludedResourceTypes.size !== 0 ) { + if ( resourceTypes.size !== 0 ) { return; } + rule.condition.excludedResourceTypes = Array.from(excludedResourceTypes).sort(); + } + if ( priority !== 0 ) { + rule.priority = priority; + } + return rule; +} + +/******************************************************************************/ + +export function parseFilters(text) { + if ( text.startsWith('---') ) { return; } + if ( text.endsWith('---') ) { return; } + const lines = text.split(/\n/); + if ( lines.some(a => a.startsWith(' ')) ) { return; } + let rules = []; + const parser = new sfp.AstFilterParser({ trustedSource: true }); + for ( const line of lines ) { + parser.parse(line); + if ( parser.isNetworkFilter() === false ) { continue; } + const rule = parseNetworkFilter(parser); + if ( rule === undefined ) { continue; } + rules.push(rule); + } + rules = minimizeRuleset(rules); + rules = minimizeRules(rules); + rules = validateRules(rules); + return rules; +} diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/unpicker-ui.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/unpicker-ui.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/unpicker-ui.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/unpicker-ui.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,171 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { dom, qs$, qsa$ } from './dom.js'; +import { faIconsInit } from './fa-icons.js'; +import { toolOverlay } from './tool-overlay-ui.js'; + +/******************************************************************************/ + +function onMinimizeClicked() { + dom.cl.toggle(dom.root, 'minimized'); +} + +/******************************************************************************/ + +function highlight() { + const selectors = []; + for ( const selectorElem of qsa$('#customFilters .customFilter.on') ) { + selectors.push(selectorElem.dataset.selector); + } + if ( selectors.length !== 0 ) { + toolOverlay.postMessage({ + what: 'highlightFromSelector', + selector: selectors.join(','), + scrollTo: true, + }); + } else { + toolOverlay.postMessage({ what: 'unhighlight' }); + } +} + +/******************************************************************************/ + +function onFilterClicked(ev) { + const target = ev.target; + const filterElem = target.closest('.customFilter'); + if ( filterElem === null ) { return; } + const selectorElem = qs$(filterElem, ':scope > span.selector'); + if ( target === selectorElem ) { + if ( dom.cl.has(filterElem, 'on') ) { + dom.cl.remove(filterElem, 'on'); + } else { + dom.cl.remove('.customFilter.on', 'on'); + dom.cl.add(filterElem, 'on'); + } + highlight(); + return; + } + const selector = filterElem.dataset.selector; + const trashElem = qs$(filterElem, ':scope > span.remove'); + if ( target === trashElem ) { + dom.cl.add(filterElem, 'removed'); + dom.cl.remove(filterElem, 'on'); + toolOverlay.sendMessage({ what: 'removeCustomFilters', + hostname: toolOverlay.url.hostname, + selectors: [ selector ], + }).then(( ) => { + autoSelectFilter(); + }); + return; + } + const undoElem = qs$(filterElem, ':scope > span.undo'); + if ( target === undoElem ) { + dom.cl.remove(filterElem, 'removed'); + toolOverlay.sendMessage({ what: 'addCustomFilters', + hostname: toolOverlay.url.hostname, + selectors: [ selector ], + }).then(( ) => { + dom.cl.remove('.customFilter.on', 'on'); + dom.cl.add(filterElem, 'on'); + highlight(); + }); + return; + } +} + +/******************************************************************************/ + +function autoSelectFilter() { + let filterElem = qs$('.customFilter.on'); + if ( filterElem !== null ) { return; } + filterElem = qs$('.customFilter:not(.removed)'); + if ( filterElem !== null ) { + dom.cl.add(filterElem, 'on'); + } + highlight(); +} + +/******************************************************************************/ + +function populateFilters(selectors) { + const container = qs$('#customFilters'); + dom.clear(container); + const rowTemplate = qs$('template#customFilterRow'); + for ( const selector of selectors ) { + const fragment = rowTemplate.content.cloneNode(true); + const row = qs$(fragment, '.customFilter'); + row.dataset.selector = selector; + let text = selector; + if ( selector.startsWith('{') ) { + const o = JSON.parse(selector); + text = o.raw; + } + qs$(row, '.selector').textContent = text; + container.append(fragment); + } + faIconsInit(container); + autoSelectFilter(); +} + +/******************************************************************************/ + +async function startUnpicker() { + const selectors = await toolOverlay.sendMessage({ + what: 'customFiltersFromHostname', + hostname: toolOverlay.url.hostname, + }) + if ( selectors.length === 0 ) { + return quitUnpicker(); + } + await toolOverlay.postMessage({ what: 'terminateCustomFilters' }); + await toolOverlay.postMessage({ what: 'startTool' }); + populateFilters(selectors); + dom.on('#minimize', 'click', onMinimizeClicked); + dom.on('#customFilters', 'click', onFilterClicked); + dom.on('#quit', 'click', quitUnpicker); +} + +/******************************************************************************/ + +async function quitUnpicker() { + await toolOverlay.postMessage({ what: 'startCustomFilters' }); + toolOverlay.stop(); +} + +/******************************************************************************/ + +function onMessage(msg) { + switch ( msg.what ) { + case 'startTool': + startUnpicker(); + break; + default: + break; + } +} + +/******************************************************************************/ + +// Wait for the content script to establish communication +toolOverlay.start(onMessage); + +/******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/utils.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/utils.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/utils.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/utils.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,12 +19,17 @@ Home: https://github.com/gorhill/uBlock */ +import { + browser, + runtime, +} from './ext.js'; + /******************************************************************************/ function parsedURLromOrigin(origin) { try { return new URL(origin); - } catch(ex) { + } catch { } } @@ -100,15 +105,13 @@ /******************************************************************************/ +const matchFromHostname = hn => + hn === '*' || hn === 'all-urls' ? '' : `*://*.${hn}/*`; + const matchesFromHostnames = hostnames => { const out = []; for ( const hn of hostnames ) { - if ( hn === '*' || hn === 'all-urls' ) { - out.length = 0; - out.push(''); - break; - } - out.push(`*://*.${hn}/*`); + out.push(matchFromHostname(hn)); } return out; }; @@ -116,7 +119,7 @@ const hostnamesFromMatches = origins => { const out = []; for ( const origin of origins ) { - if ( origin === '' ) { + if ( origin === '' || origin === '*://*/*' ) { out.push('all-urls'); continue; } @@ -136,6 +139,76 @@ /******************************************************************************/ +// https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/manifest.json/host_permissions#requested_permissions_and_user_prompts +// "Users can grant or revoke host permissions on an ad hoc basis. Therefore, +// most browsers treat host_permissions as optional." + +async function hasBroadHostPermissions() { + return browser.permissions.getAll().then(permissions => + permissions.origins.includes('') || + permissions.origins.includes('*://*/*') + ).catch(( ) => false); +} + +/******************************************************************************/ + +async function gotoURL(url, type) { + const pageURL = new URL(url, runtime.getURL('/')); + const tabs = await browser.tabs.query({ + url: pageURL.href, + windowType: type !== 'popup' ? 'normal' : 'popup' + }); + + if ( Array.isArray(tabs) && tabs.length !== 0 ) { + const { windowId, id } = tabs[0]; + return Promise.all([ + browser.windows.update(windowId, { focused: true }), + browser.tabs.update(id, { active: true }), + ]); + } + + if ( type === 'popup' ) { + return browser.windows.create({ + type: 'popup', + url: pageURL.href, + }); + } + + return browser.tabs.create({ + active: true, + url: pageURL.href, + }); +} + +/******************************************************************************/ + +// Important: We need to sort the arrays for fast comparison +const strArrayEq = (a = [], b = [], sort = true) => { + const alen = a.length; + if ( alen !== b.length ) { return false; } + if ( sort ) { a.sort(); b.sort(); } + for ( let i = 0; i < alen; i++ ) { + if ( a[i] !== b[i] ) { return false; } + } + return true; +}; + +/******************************************************************************/ + +// The goal is just to be able to find out whether a specific version is older +// than another one. + +export function intFromVersion(version) { + const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version); + if ( match === null ) { return 0; } + const year = parseInt(match[1], 10); + const monthday = parseInt(match[2], 10); + const min = parseInt(match[3], 10); + return (year - 2022) * (1232 * 2400) + monthday * 2400 + min; +} + +/******************************************************************************/ + export { broadcastMessage, parsedURLromOrigin, @@ -144,6 +217,10 @@ isDescendantHostnameOfIter, intersectHostnameIters, subtractHostnameIters, + matchFromHostname, matchesFromHostnames, hostnamesFromMatches, + hasBroadHostPermissions, + gotoURL, + strArrayEq, }; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/zapper-ui.js ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/zapper-ui.js --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/js/zapper-ui.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/js/zapper-ui.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,133 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { dom } from './dom.js'; +import { toolOverlay } from './tool-overlay-ui.js'; + +/******************************************************************************/ + +function onSvgClicked(ev) { + // If zap mode, highlight element under mouse, this makes the zapper usable + // on touch screens. + toolOverlay.postMessage({ + what: 'zapElementAtPoint', + mx: ev.clientX, + my: ev.clientY, + options: { + stay: true, + highlight: dom.cl.has(dom.root, 'mobile') && + ev.target !== toolOverlay.svgIslands, + }, + }); +} + +/******************************************************************************/ + +const onSvgTouch = (( ) => { + let startX = 0, startY = 0; + let t0 = 0; + return ev => { + if ( ev.type === 'touchstart' ) { + startX = ev.touches[0].screenX; + startY = ev.touches[0].screenY; + t0 = ev.timeStamp; + return; + } + if ( startX === undefined ) { return; } + const stopX = ev.changedTouches[0].screenX; + const stopY = ev.changedTouches[0].screenY; + const distance = Math.sqrt( + Math.pow(stopX - startX, 2) + + Math.pow(stopY - startY, 2) + ); + // Interpret touch events as a tap if: + // - Swipe is not valid; and + // - The time between start and stop was less than 200ms. + const duration = ev.timeStamp - t0; + if ( distance >= 32 || duration >= 200 ) { return; } + onSvgClicked({ + type: 'touch', + target: ev.target, + clientX: ev.changedTouches[0].pageX, + clientY: ev.changedTouches[0].pageY, + }); + ev.preventDefault(); + }; +})(); + +/******************************************************************************/ + +function onKeyPressed(ev) { + // Delete + if ( ev.key === 'Delete' || ev.key === 'Backspace' ) { + toolOverlay.postMessage({ + what: 'zapElementAtPoint', + options: { stay: true }, + }); + return; + } + // Esc + if ( ev.key === 'Escape' || ev.which === 27 ) { + quitZapper(); + return; + } +} + +/******************************************************************************/ + +function startZapper() { + toolOverlay.postMessage({ what: 'startTool' }); + self.addEventListener('keydown', onKeyPressed, true); + dom.on('svg#overlay', 'click', onSvgClicked); + dom.on('svg#overlay', 'touchstart', onSvgTouch, { passive: true }); + dom.on('svg#overlay', 'touchend', onSvgTouch); + dom.on('#quit', 'click', quitZapper ); + dom.on('#pick', 'click', resetZapper ); + toolOverlay.highlightElementUnderMouse(true); +} + +function quitZapper() { + self.removeEventListener('keydown', onKeyPressed, true); + toolOverlay.stop(); +} + +function resetZapper() { + toolOverlay.postMessage({ what: 'unhighlight' }); +} + +/******************************************************************************/ + +function onMessage(msg) { + switch ( msg.what ) { + case 'startTool': + startZapper(); + break; + default: + break; + } +} + +/******************************************************************************/ + +// Wait for the content script to establish communication +toolOverlay.start(onMessage); + +/******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/lib/codemirror/README.md ublock-origin-1.67.0+dfsg/platform/mv3/extension/lib/codemirror/README.md --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/lib/codemirror/README.md 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/lib/codemirror/README.md 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,9 @@ +Steps to build `cm6.bundle.ubol.min.js` -- command line from repo root: + +- `git submodule init platform/mv3/extension/lib/codemirror/codemirror-ubol` +- `cd platform/mv3/extension/lib/codemirror/codemirror-ubol/` + - We are now in a customized repo forked from +- `npm install` +- `npm run build` +- `cm6.bundle.ubol.min.js` should be in `dist` directory +- This is the origin of the `cm6.bundle.ubol.min.js` in the current directory diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/lib/codemirror/codemirror.LICENSE ublock-origin-1.67.0+dfsg/platform/mv3/extension/lib/codemirror/codemirror.LICENSE --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/lib/codemirror/codemirror.LICENSE 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/lib/codemirror/codemirror.LICENSE 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2018-2021 by Marijn Haverbeke and others + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/managed_storage.json ublock-origin-1.67.0+dfsg/platform/mv3/extension/managed_storage.json --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/managed_storage.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/managed_storage.json 2025-10-25 19:32:51.000000000 +0000 @@ -2,8 +2,14 @@ "$schema": "http://json-schema.org/draft-03/schema#", "type": "object", "properties": { - "noFiltering": { - "title": "List of domains for which no filtering should occur", + "defaultFiltering": { + "title": "The default filtering mode", + "description": "Can be one of \"none\", \"basic\", \"optimal\", \"complete\".", + "type": "string" + }, + "disabledFeatures": { + "title": "User interface features to disable", + "description": "A list of tokens, each of which correspond to a user interface feature to disable.", "type": "array", "items": { "type": "string" } }, @@ -11,17 +17,24 @@ "title": "Disable first run page", "type": "boolean" }, + "noFiltering": { + "title": "List of domains for which no filtering should occur", + "type": "array", + "items": { "type": "string" } + }, "rulesets": { "title": "Rulesets to add/remove", "description": "Prefix a ruleset id with '+' to add, or '-' to remove. Use '-*' to disable all non-default lists.", "type": "array", "items": { "type": "string" } }, - "disabledFeatures": { - "title": "User interface features to disable", - "description": "A list of tokens, each of which correspond to a user interface feature to disable.", - "type": "array", - "items": { "type": "string" } + "showBlockedCount": { + "title": "Enable/disable toolbar icon count badge", + "type": "boolean" + }, + "strictBlockMode": { + "title": "Enable/disable strict blocking", + "type": "boolean" } } } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/matched-rules.html ublock-origin-1.67.0+dfsg/platform/mv3/extension/matched-rules.html --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/matched-rules.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/matched-rules.html 2025-10-25 19:32:51.000000000 +0000 @@ -3,6 +3,7 @@ + Matched rules diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/picker-ui.html ublock-origin-1.67.0+dfsg/platform/mv3/extension/picker-ui.html --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/picker-ui.html 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/picker-ui.html 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,56 @@ + + + + + + +uBO Lite Zapper + + + + + + + + + + + + + + + + + + + diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/popup.html ublock-origin-1.67.0+dfsg/platform/mv3/extension/popup.html --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/popup.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/popup.html 2025-10-25 19:32:51.000000000 +0000 @@ -4,6 +4,7 @@ + @@ -12,7 +13,7 @@ - +
    ­
    @@ -26,31 +27,31 @@

    _
    -
    - - - - list-altShow matched rules - comment-alt - cogs -
    - -
    -
    -
    -
    - - _angle-up +
    + + + bolt + _ + + + eye-slash + _ + + + eye-open + _ - - angle-up_ + + comment-alt + _
    -
    - -
    -

    + +
    + list-altShow matched rules + cogs +
    diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/report.html ublock-origin-1.67.0+dfsg/platform/mv3/extension/report.html --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/report.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/report.html 2025-10-25 19:32:51.000000000 +0000 @@ -3,20 +3,22 @@ + uBO Lite — Report - + +
    -

    +


    @@ -49,6 +51,12 @@

    +
    +
    +
    +
    
    +    
    +
    diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/strictblock.html ublock-origin-1.67.0+dfsg/platform/mv3/extension/strictblock.html --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/strictblock.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/strictblock.html 2025-10-25 19:32:51.000000000 +0000 @@ -3,6 +3,7 @@ + diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/unpicker-ui.html ublock-origin-1.67.0+dfsg/platform/mv3/extension/unpicker-ui.html --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/unpicker-ui.html 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/unpicker-ui.html 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,40 @@ + + + + + + +uBO Lite Zapper + + + + + + + + + + + + + + + + + + + + + diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/extension/zapper-ui.html ublock-origin-1.67.0+dfsg/platform/mv3/extension/zapper-ui.html --- ublock-origin-1.62.0+dfsg/platform/mv3/extension/zapper-ui.html 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/extension/zapper-ui.html 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,32 @@ + + + + + + +uBO Lite Zapper + + + + + + + + + + + + + + + diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/firefox/background.html ublock-origin-1.67.0+dfsg/platform/mv3/firefox/background.html --- ublock-origin-1.62.0+dfsg/platform/mv3/firefox/background.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/firefox/background.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ - - - - -uBlock Origin Background Page - - - - - diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/firefox/manifest.json ublock-origin-1.67.0+dfsg/platform/mv3/firefox/manifest.json --- ublock-origin-1.62.0+dfsg/platform/mv3/firefox/manifest.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/firefox/manifest.json 2025-10-25 19:32:51.000000000 +0000 @@ -16,10 +16,18 @@ "browser_specific_settings": { "gecko": { "id": "uBOLiteRedux@raymondhill.net", - "strict_min_version": "127.0" + "strict_min_version": "128.0" }, "gecko_android": { - "strict_min_version": "127.0" + "strict_min_version": "128.0" + } + }, + "commands": { + "enter-zapper-mode": { + "description": "__MSG_zapperTipEnter__" + }, + "enter-picker-mode": { + "description": "__MSG_pickerTipEnter__" } }, "declarative_net_request": { @@ -40,7 +48,7 @@ "open_in_tab": true, "page": "dashboard.html" }, - "optional_permissions": [ + "host_permissions": [ "" ], "permissions": [ @@ -58,6 +66,30 @@ ], "matches": [ "" + ] + }, + { + "resources": [ + "/zapper-ui.html" + ], + "matches": [ + "" + ] + }, + { + "resources": [ + "/picker-ui.html" + ], + "matches": [ + "" + ] + }, + { + "resources": [ + "/unpicker-ui.html" + ], + "matches": [ + "" ] } ] diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/firefox/patch-ruleset.js ublock-origin-1.67.0+dfsg/platform/mv3/firefox/patch-ruleset.js --- ublock-origin-1.62.0+dfsg/platform/mv3/firefox/patch-ruleset.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/firefox/patch-ruleset.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,30 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +export function patchRuleset(ruleset) { + const out = []; + for ( const rule of ruleset ) { + const condition = rule.condition; + if ( Array.isArray(condition.responseHeaders) ) { continue; } + out.push(rule); + } + return out; +} diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/make-rulesets.js ublock-origin-1.67.0+dfsg/platform/mv3/make-rulesets.js --- ublock-origin-1.62.0+dfsg/platform/mv3/make-rulesets.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/make-rulesets.js 2025-10-25 19:32:51.000000000 +0000 @@ -31,8 +31,8 @@ mergeRules, } from './js/static-dnr-filtering.js'; +import { execSync } from 'node:child_process'; import fs from 'fs/promises'; -import https from 'https'; import path from 'path'; import process from 'process'; import redirectResourcesMap from './js/redirect-resources.js'; @@ -62,16 +62,22 @@ const cacheDir = `${outputDir}/../mv3-data`; const rulesetDir = `${outputDir}/rulesets`; const scriptletDir = `${rulesetDir}/scripting`; +const envExtra = (( ) => { + const env = commandLineArgs.get('env'); + return env ? env.split('|') : []; +})(); const env = [ platform, + 'native_css_has', 'mv3', 'ublock', 'ubol', 'user_stylesheet', + ...envExtra, ]; -if ( platform !== 'firefox' ) { - env.push('native_css_has'); +if ( platform === 'edge' ) { + env.push('chromium'); } /******************************************************************************/ @@ -91,50 +97,70 @@ /******************************************************************************/ +const consoleLog = console.log; const stdOutput = []; -const log = (text, silent = false) => { +const log = (text, silent = true) => { stdOutput.push(text); if ( silent === false ) { - console.log(text); + consoleLog(text); } }; +console.log = log; + +const logProgress = text => { + process?.stdout?.clearLine?.(); + process?.stdout?.cursorTo?.(0); + process?.stdout?.write?.(text.length > 120 ? `${text.slice(0, 119)}… ` : `${text} `); +}; + /******************************************************************************/ -const urlToFileName = url => { - return url +async function fetchText(url, cacheDir) { + logProgress(`Reading locally cached ${url}`); + const fname = url .replace(/^https?:\/\//, '') - .replace(/\//g, '_'); -}; + .replace(/\//g, '_');(url); + const content = await fs.readFile( + `${cacheDir}/${fname}`, + { encoding: 'utf8' } + ).catch(( ) => { }); + if ( content !== undefined ) { + log(`\tFetched local ${url}`); + return { url, content }; + } + logProgress(`Fetching remote ${url}`); + log(`\tFetching remote ${url}`); + const response = await fetch(url).catch(( ) => { }); + if ( response === undefined ) { + return { url, error: `Fetching failed: ${url}` }; + } + let text; + if ( response.ok ) { + text = await response.text().catch(( ) => { }); + } else { + text = await fallbackFetchText(url).catch(( ) => { }); + } + if ( text === undefined ) { + return { url, error: `Fetching text content failed: ${url}` }; + } + writeFile(`${cacheDir}/${fname}`, text); + return { url, content: text }; +} -const fetchText = (url, cacheDir) => { - return new Promise((resolve, reject) => { - const fname = urlToFileName(url); - fs.readFile(`${cacheDir}/${fname}`, { encoding: 'utf8' }).then(content => { - log(`\tFetched local ${url}`); - resolve({ url, content }); - }).catch(( ) => { - log(`\tFetching remote ${url}`); - https.get(url, response => { - const data = []; - response.on('data', chunk => { - data.push(chunk.toString()); - }); - response.on('end', ( ) => { - const content = data.join(''); - try { - writeFile(`${cacheDir}/${fname}`, content); - } catch (ex) { - } - resolve({ url, content }); - }); - }).on('error', error => { - reject(error); - }); - }); - }); -}; +async function fallbackFetchText(url) { + const match = /^https:\/\/raw\.githubusercontent\.com\/([^/]+)\/([^/]+)\/master\/([^?]+)/.exec(url); + if ( match === null ) { return; } + logProgress(`\tGitHub CLI-fetching remote ${url}`); + // https://docs.github.com/en/rest/repos/contents + const content = execSync(`gh api \ + -H "Accept: application/vnd.github.raw+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + /repos/${match[1]}/${match[2]}/contents/${match[3]} \ + `, { encoding: 'utf8' }); + return content; +} /******************************************************************************/ @@ -163,10 +189,11 @@ const scriptletStats = new Map(); const genericDetails = new Map(); const requiredRedirectResources = new Set(); +let networkBad = new Set(); // This will be used to sign our inserted `!#trusted on` directives const secret = createHash('sha256').update(randomBytes(16)).digest('hex').slice(0,16); -log(`Secret: ${secret}`); +log(`Secret: ${secret}`, false); /******************************************************************************/ @@ -230,34 +257,33 @@ continue; } fetchedURLs.add(part.url); - if ( part.url.startsWith('https://ublockorigin.github.io/uAssets/filters/') ) { + if ( + assetDetails.trusted || + part.url.startsWith('https://ublockorigin.github.io/uAssets/filters/') + ) { newParts.push(`!#trusted on ${secret}`); } newParts.push( fetchText(part.url, cacheDir).then(details => { - const { url } = details; + const { url, error } = details; + if ( error !== undefined ) { return details; } const content = details.content.trim(); - if ( typeof content === 'string' && content !== '' ) { - if ( - content.startsWith('<') === false || - content.endsWith('>') === false - ) { - return { url, content }; - } + if ( /* content === '' || */ /^<.*>$/.test(content) ) { + return { url, error: `Bad content: ${url}` }; } - log(`No valid content for ${details.name}`); - return { url, content: '' }; + return { url, content }; }) ); newParts.push(`!#trusted off ${secret}`); } + if ( parts.some(v => typeof v === 'object' && v.error) ) { return; } parts = await Promise.all(newParts); parts = sfp.utils.preparser.expandIncludes(parts, env); } const text = parts.join('\n'); if ( text === '' ) { - log('No filterset found'); + log('No filterset found', false); } return text; } @@ -271,30 +297,9 @@ rule.condition !== undefined && rule.condition.regexFilter !== undefined; -const isRedirect = rule => { - if ( isUnsupported(rule) ) { return false; } - if ( rule.action.type !== 'redirect' ) { return false; } - if ( rule.action.redirect?.extensionPath !== undefined ) { return true; } - if ( rule.action.redirect?.transform?.path !== undefined ) { return true; } - return false; -}; - -const isModifyHeaders = rule => +const isGood = rule => isUnsupported(rule) === false && - rule.action.type === 'modifyHeaders'; - -const isRemoveparam = rule => - isUnsupported(rule) === false && - rule.action.type === 'redirect' && - rule.action.redirect.transform !== undefined; - -const isSafe = rule => - isUnsupported(rule) === false && - rule.action !== undefined && ( - rule.action.type === 'block' || - rule.action.type === 'allow' || - rule.action.type === 'allowAllRequests' - ); + /^(allow|block|redirect|modifyHeaders|allowAllRequests)$/.test(rule.action?.type); const isURLSkip = rule => isUnsupported(rule) === false && @@ -303,6 +308,16 @@ /******************************************************************************/ +async function patchRuleset(ruleset) { + return import(`./${platform}/patch-ruleset.js`).then(module => { + return module.patchRuleset(ruleset) + }).catch(( ) => { + return ruleset; + }); +} + +/******************************************************************************/ + // Two distinct hostnames: // www.example.com // example.com @@ -358,6 +373,23 @@ * */ function toJSONRuleset(ruleset) { + const nodupProps = [ 'domains', 'excludedDomains', 'requestDomains', 'excludedRequestDomains', 'initiatorDomains', 'excludedInitiatorDomains' ]; + for ( const { condition } of ruleset ) { + if ( condition === undefined ) { continue; } + for ( const prop of nodupProps ) { + if ( condition[prop] === undefined ) { continue; } + condition[prop] = Array.from(new Set(condition[prop])); + } + } + const sortProps = [ 'requestDomains', 'initiatorDomains', 'domains' ]; + ruleset.sort((a, b) => { + let aLen = 0, bLen = 0; + for ( const prop of sortProps ) { + aLen += a.condition[prop]?.length ?? 0; + bLen += b.condition[prop]?.length ?? 0; + } + return bLen - aLen; + }); const replacer = (k, v) => { if ( k.startsWith('_') ) { return; } if ( Array.isArray(v) ) { @@ -374,7 +406,9 @@ }; const indent = ruleset.length > 10 ? undefined : 1; const out = []; + let id = 1; for ( const rule of ruleset ) { + rule.id = id++; out.push(JSON.stringify(rule, replacer, indent)); } return `[\n${out.join(',\n')}\n]\n`; @@ -394,13 +428,11 @@ if ( condition.excludedResponseHeaders ) { return; } if ( condition.initiatorDomains ) { return; } if ( condition.excludedInitiatorDomains ) { return; } - if ( condition.excludedRequestDomains ) { return; } const { resourceTypes } = condition; if ( resourceTypes === undefined ) { if ( condition.requestDomains === undefined ) { return; } - } else { - if ( resourceTypes.length !== 1 ) { return; } - if ( resourceTypes[0] !== 'main_frame' ) { return; } + } else if ( resourceTypes.includes('main_frame') === false ) { + return; } let regexFilter; if ( condition.urlFilter ) { @@ -410,9 +442,7 @@ } else { regexFilter = '^https?://.*'; } - if ( - regexFilter.startsWith('^') === false - ) { + if ( regexFilter.startsWith('^') === false ) { regexFilter = `^.*${regexFilter}`; } if ( @@ -422,7 +452,7 @@ ) { regexFilter = `${regexFilter}.*`; } - const strictBlockRule = { + const strictBlockRule = out.get(regexFilter) || { action: { type: 'redirect', redirect: { @@ -436,9 +466,24 @@ priority: 29, }; if ( condition.requestDomains ) { - strictBlockRule.condition.requestDomains = condition.requestDomains.slice(); + strictBlockRule.condition.requestDomains ??= []; + strictBlockRule.condition.requestDomains = Array.from( + new Set([ + ...strictBlockRule.condition.requestDomains, + ...condition.requestDomains, + ]) + ); + } + if ( condition.excludedRequestDomains ) { + strictBlockRule.condition.excludedRequestDomains ??= []; + strictBlockRule.condition.excludedRequestDomains = Array.from( + new Set([ + ...strictBlockRule.condition.excludedRequestDomains, + ...condition.excludedRequestDomains, + ]) + ); } - out.set(toStrictBlockRule.ruleId++, strictBlockRule); + out.set(regexFilter, strictBlockRule); } toStrictBlockRule.ruleId = 1; @@ -473,42 +518,27 @@ } } - const plainGood = rules.filter(rule => isSafe(rule) && isRegex(rule) === false); - log(`\tPlain good: ${plainGood.length}`); - log(plainGood + const staticRules = await patchRuleset( + rules.filter(rule => isGood(rule) && isRegex(rule) === false) + ); + log(`\tStatic rules: ${staticRules.length}`); + log(staticRules .filter(rule => Array.isArray(rule._warning)) .map(rule => rule._warning.map(v => `\t\t${v}`)) .join('\n'), true ); - const regexes = rules.filter(rule => isSafe(rule) && isRegex(rule)); - log(`\tMaybe good (regexes): ${regexes.length}`); - - const redirects = rules.filter(rule => - isUnsupported(rule) === false && - isRedirect(rule) + const regexRules = await patchRuleset( + rules.filter(rule => isGood(rule) && isRegex(rule)) ); - redirects.forEach(rule => { - if ( rule.action.redirect.extensionPath === undefined ) { return; } + log(`\tMaybe good (regexes): ${regexRules.length}`); + + staticRules.forEach(rule => { + if ( rule.action.redirect?.extensionPath === undefined ) { return; } requiredRedirectResources.add( rule.action.redirect.extensionPath.replace(/^\/+/, '') ); }); - log(`\tredirect=: ${redirects.length}`); - - const removeparamsGood = rules.filter(rule => - isUnsupported(rule) === false && isRemoveparam(rule) - ); - const removeparamsBad = rules.filter(rule => - isUnsupported(rule) && isRemoveparam(rule) - ); - log(`\tremoveparams= (accepted/discarded): ${removeparamsGood.length}/${removeparamsBad.length}`); - - const modifyHeaders = rules.filter(rule => - isUnsupported(rule) === false && - isModifyHeaders(rule) - ); - log(`\tmodifyHeaders=: ${modifyHeaders.length}`); const urlskips = new Map(); for ( const rule of rules ) { @@ -557,71 +587,38 @@ log(`\tUnsupported: ${bad.length}`); log(bad.map(rule => rule._error.map(v => `\t\t${v}`)).join('\n'), true); - writeFile( - `${rulesetDir}/main/${assetDetails.id}.json`, - toJSONRuleset(plainGood) + writeFile(`${rulesetDir}/main/${assetDetails.id}.json`, + toJSONRuleset(staticRules) ); - if ( regexes.length !== 0 ) { - writeFile( - `${rulesetDir}/regex/${assetDetails.id}.json`, - toJSONRuleset(regexes) - ); - } - - if ( removeparamsGood.length !== 0 ) { - writeFile( - `${rulesetDir}/removeparam/${assetDetails.id}.json`, - toJSONRuleset(removeparamsGood) - ); - } - - if ( redirects.length !== 0 ) { - writeFile( - `${rulesetDir}/redirect/${assetDetails.id}.json`, - toJSONRuleset(redirects) - ); - } - - if ( modifyHeaders.length !== 0 ) { - writeFile( - `${rulesetDir}/modify-headers/${assetDetails.id}.json`, - toJSONRuleset(modifyHeaders) + if ( regexRules.length !== 0 ) { + writeFile(`${rulesetDir}/regex/${assetDetails.id}.json`, + toJSONRuleset(regexRules) ); } const strictBlocked = new Map(); - for ( const rule of plainGood ) { + for ( const rule of staticRules ) { toStrictBlockRule(rule, strictBlocked); } if ( strictBlocked.size !== 0 ) { mergeRules(strictBlocked, 'requestDomains'); - let id = 1; - for ( const rule of strictBlocked.values() ) { - rule.id = id++; - } - writeFile( - `${rulesetDir}/strictblock/${assetDetails.id}.json`, + writeFile(`${rulesetDir}/strictblock/${assetDetails.id}.json`, toJSONRuleset(Array.from(strictBlocked.values())) ); } if ( urlskips.size !== 0 ) { - writeFile( - `${rulesetDir}/urlskip/${assetDetails.id}.json`, + writeFile(`${rulesetDir}/urlskip/${assetDetails.id}.json`, JSON.stringify(Array.from(urlskips.values()), null, 1) ); } return { total: rules.length, - plain: plainGood.length, - discarded: removeparamsBad.length, + plain: staticRules.length, rejected: bad.length, - regex: regexes.length, - removeparam: removeparamsGood.length, - redirect: redirects.length, - modifyHeaders: modifyHeaders.length, + regex: regexRules.length, strictblock: strictBlocked.size, urlskip: urlskips.size, }; @@ -668,61 +665,128 @@ /******************************************************************************/ -async function processGenericCosmeticFilters(assetDetails, bucketsMap, exceptionSet) { - if ( bucketsMap === undefined ) { return 0; } - if ( exceptionSet ) { - for ( const [ hash, selectors ] of bucketsMap ) { - let i = selectors.length; - while ( i-- ) { - const selector = selectors[i]; - if ( exceptionSet.has(selector) === false ) { continue; } - selectors.splice(i, 1); - //log(`\tRemoving excepted generic filter ##${selector}`); +// http://www.cse.yorku.ca/~oz/hash.html#djb2 +// Must mirror content script surveyor's version + +async function processGenericCosmeticFilters( + assetDetails, + selectorList, + exceptionList, + declarativeMap +) { + const exceptionSet = new Set( + exceptionList && + exceptionList.filter(a => a.key !== undefined).map(a => a.selector) + ); + + const genericSelectorMap = new Map(); + if ( selectorList ) { + for ( const { key, selector } of selectorList ) { + if ( key === undefined ) { continue; } + if ( exceptionSet.has(selector) ) { continue; } + const type = key.charCodeAt(0); + const hash = hashFromStr(type, key.slice(1)); + const selectors = genericSelectorMap.get(hash); + if ( selectors === undefined ) { + genericSelectorMap.set(hash, selector) + } else { + genericSelectorMap.set(hash, `${selectors},\n${selector}`) } - if ( selectors.length === 0 ) { - bucketsMap.delete(hash); + } + } + + // Specific exceptions + const genericExceptionSieve = new Set(); + const genericExceptionMap = new Map(); + if ( declarativeMap ) { + for ( const [ exception, details ] of declarativeMap ) { + if ( details.rejected ) { continue; } + if ( details.key === undefined ) { continue; } + if ( details.matches !== undefined ) { continue; } + if ( details.excludeMatches === undefined ) { continue; } + const type = details.key.charCodeAt(0); + const hash = hashFromStr(type, details.key.slice(1)); + genericExceptionSieve.add(hash); + for ( const hn of details.excludeMatches ) { + const exceptions = genericExceptionMap.get(hn); + if ( exceptions === undefined ) { + genericExceptionMap.set(hn, exception); + } else { + genericExceptionMap.set(hn, `${exceptions}\n${exception}`); + } } } } - if ( bucketsMap.size === 0 ) { return 0; } - const bucketsList = Array.from(bucketsMap); - const count = bucketsList.reduce((a, v) => a += v[1].length, 0); - if ( count === 0 ) { return 0; } - const selectorLists = bucketsList.map(v => [ v[0], v[1].join(',') ]); - const originalScriptletMap = await loadAllSourceScriptlets(); + if ( genericSelectorMap.size === 0 ) { + if ( genericExceptionMap.size === 0 ) { return 0; } + } + + const originalScriptletMap = await loadAllSourceScriptlets(); let patchedScriptlet = originalScriptletMap.get('css-generic').replace( '$rulesetId$', assetDetails.id ); patchedScriptlet = safeReplace(patchedScriptlet, /\bself\.\$genericSelectorMap\$/, - `${JSON.stringify(selectorLists, scriptletJsonReplacer)}` + `${JSON.stringify(genericSelectorMap, scriptletJsonReplacer)}` + ); + patchedScriptlet = safeReplace(patchedScriptlet, + /\bself\.\$genericExceptionSieve\$/, + `${JSON.stringify(genericExceptionSieve, scriptletJsonReplacer)}` + ); + patchedScriptlet = safeReplace(patchedScriptlet, + /\bself\.\$genericExceptionMap\$/, + `${JSON.stringify(genericExceptionMap, scriptletJsonReplacer)}` ); - writeFile( - `${scriptletDir}/generic/${assetDetails.id}.js`, + writeFile(`${scriptletDir}/generic/${assetDetails.id}.js`, patchedScriptlet ); - log(`CSS-generic: ${count} plain CSS selectors`); + log(`CSS-generic: ${genericExceptionSieve.size} specific CSS exceptions`); + log(`CSS-generic: ${genericSelectorMap.size} plain CSS selectors`); - return count; + return genericSelectorMap.size + genericExceptionSieve.size; } +const hashFromStr = (type, s) => { + const len = s.length; + const step = len + 7 >>> 3; + let hash = (type << 5) + type ^ len; + for ( let i = 0; i < len; i += step ) { + hash = (hash << 5) + hash ^ s.charCodeAt(i); + } + return hash & 0xFFF; +}; + /******************************************************************************/ -async function processGenericHighCosmeticFilters(assetDetails, selectorSet, exceptionSet) { - if ( selectorSet === undefined ) { return 0; } - if ( exceptionSet ) { - for ( const selector of selectorSet ) { - if ( exceptionSet.has(selector) === false ) { continue; } - selectorSet.delete(selector); - //log(`\tRemoving excepted generic filter ##${selector}`); - } +async function processGenericHighCosmeticFilters( + assetDetails, + genericSelectorList, + genericExceptionList +) { + if ( genericSelectorList === undefined ) { return 0; } + const genericSelectorSet = new Set( + genericSelectorList + .filter(a => a.key === undefined) + .map(a => a.selector) + ); + // https://github.com/uBlockOrigin/uBOL-home/issues/365 + if ( genericExceptionList ) { + for ( const entry of genericExceptionList ) { + if ( entry.key !== undefined ) { continue; } + globalHighlyGenericExceptionSet.add(entry.selector); + } + } + for ( const selector of globalHighlyGenericExceptionSet ) { + if ( genericSelectorSet.has(selector) === false ) { continue; } + genericSelectorSet.delete(selector); + log(`\tRemoving excepted highly generic filter ##${selector}`); } - if ( selectorSet.size === 0 ) { return 0; } - const selectorLists = Array.from(selectorSet).sort().join(',\n'); + if ( genericSelectorSet.size === 0 ) { return 0; } + const selectorLists = Array.from(genericSelectorSet).sort().join(',\n'); const originalScriptletMap = await loadAllSourceScriptlets(); let patchedScriptlet = originalScriptletMap.get('css-generichigh').replace( @@ -734,16 +798,17 @@ selectorLists ); - writeFile( - `${scriptletDir}/generichigh/${assetDetails.id}.css`, + writeFile(`${scriptletDir}/generichigh/${assetDetails.id}.css`, patchedScriptlet ); - log(`CSS-generic-high: ${selectorSet.size} plain CSS selectors`); + log(`CSS-generic-high: ${genericSelectorSet.size} plain CSS selectors`); - return selectorSet.size; + return genericSelectorSet.size; } +const globalHighlyGenericExceptionSet = new Set(); + /******************************************************************************/ // This merges selectors which are used by the same hostnames @@ -839,22 +904,33 @@ /******************************************************************************/ function argsMap2List(argsMap, hostnamesMap) { - const argsList = []; + const argsList = [ '' ]; const indexMap = new Map(); for ( const [ id, details ] of argsMap ) { indexMap.set(id, argsList.length); argsList.push(details); } + const argsSeqs = [ 0 ]; + const argsSeqsIndices = new Map(); for ( const [ hn, ids ] of hostnamesMap ) { + const seqKey = JSON.stringify(ids); + if ( argsSeqsIndices.has(seqKey) ) { + hostnamesMap.set(hn, argsSeqsIndices.get(seqKey)); + continue; + } + const seqIndex = argsSeqs.length; + argsSeqsIndices.set(seqKey, seqIndex); + hostnamesMap.set(hn, seqIndex); if ( typeof ids === 'number' ) { - hostnamesMap.set(hn, indexMap.get(ids)); + argsSeqs.push(indexMap.get(ids)); continue; } for ( let i = 0; i < ids.length; i++ ) { - ids[i] = indexMap.get(ids[i]); + argsSeqs.push(-indexMap.get(ids[i])); } + argsSeqs[argsSeqs.length-1] = -argsSeqs[argsSeqs.length-1]; } - return argsList; + return { argsList, argsSeqs }; } /******************************************************************************/ @@ -878,38 +954,21 @@ const argsMap = domainBasedEntries.map(entry => [ entry[0], - { - a: entry[1].a ? entry[1].a.join(',\n') : undefined, - n: entry[1].n - } + entry[1].a ? entry[1].a.join('\n') : undefined, ]); const hostnamesMap = new Map(); + let hasEntities = false; for ( const [ id, details ] of domainBasedEntries ) { - if ( details.y === undefined ) { continue; } - scriptletHostnameToIdMap(details.y, id, hostnamesMap); - } - const argsList = argsMap2List(argsMap, hostnamesMap); - const entitiesMap = new Map(); - for ( const [ hn, details ] of hostnamesMap ) { - if ( hn.endsWith('.*') === false ) { continue; } - hostnamesMap.delete(hn); - entitiesMap.set(hn.slice(0, -2), details); - } - - // Extract exceptions from argsList, simplify argsList entries - const exceptionsMap = new Map(); - for ( let i = 0; i < argsList.length; i++ ) { - const details = argsList[i]; + if ( details.y ) { + scriptletHostnameToIdMap(details.y, id, hostnamesMap); + hasEntities ||= details.y.some(a => a.endsWith('.*')); + } if ( details.n ) { - for ( const hn of details.n ) { - if ( exceptionsMap.has(hn) === false ) { - exceptionsMap.set(hn, []); - } - exceptionsMap.get(hn).push(i); - } + scriptletHostnameToIdMap(details.n.map(a => `~${a}`), id, hostnamesMap); + hasEntities ||= details.n.some(a => a.endsWith('.*')); } - argsList[i] = details.a; } + const { argsList, argsSeqs } = argsMap2List(argsMap, hostnamesMap); const originalScriptletMap = await loadAllSourceScriptlets(); let patchedScriptlet = originalScriptletMap.get('css-specific').replace( @@ -921,16 +980,16 @@ `${JSON.stringify(argsList, scriptletJsonReplacer)}` ); patchedScriptlet = safeReplace(patchedScriptlet, - /\bself\.\$hostnamesMap\$/, - `${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}` + /\bself\.\$argsSeqs\$/, + `${JSON.stringify(argsSeqs, scriptletJsonReplacer)}` ); patchedScriptlet = safeReplace(patchedScriptlet, - /\bself\.\$entitiesMap\$/, - `${JSON.stringify(entitiesMap, scriptletJsonReplacer)}` + /\bself\.\$hostnamesMap\$/, + `${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}` ); patchedScriptlet = safeReplace(patchedScriptlet, - /\bself\.\$exceptionsMap\$/, - `${JSON.stringify(exceptionsMap, scriptletJsonReplacer)}` + 'self.$hasEntities$', + JSON.stringify(hasEntities) ); writeFile(`${scriptletDir}/specific/${assetDetails.id}.js`, patchedScriptlet); generatedFiles.push(`${assetDetails.id}`); @@ -938,97 +997,9 @@ if ( generatedFiles.length !== 0 ) { log(`CSS-specific: ${mapin.size} distinct filters`); log(`\tCombined into ${hostnamesMap.size} distinct hostnames`); - log(`\tCombined into ${entitiesMap.size} distinct entities`); - } - - return hostnamesMap.size + entitiesMap.size; -} - -/******************************************************************************/ - -async function processDeclarativeCosmeticFilters(assetDetails, mapin) { - if ( mapin === undefined ) { return 0; } - if ( mapin.size === 0 ) { return 0; } - - // Distinguish declarative-compiled-as-procedural from actual procedural. - const declaratives = new Map(); - mapin.forEach((details, jsonSelector) => { - const selector = JSON.parse(jsonSelector); - if ( selector.cssable !== true ) { return; } - selector.cssable = undefined; - declaratives.set(JSON.stringify(selector), details); - }); - if ( declaratives.size === 0 ) { return 0; } - - const contentArray = groupHostnamesBySelectors( - groupSelectorsByHostnames(declaratives) - ); - - const argsMap = contentArray.map(entry => [ - entry[0], - { - a: entry[1].a, - n: entry[1].n, - } - ]); - const hostnamesMap = new Map(); - for ( const [ id, details ] of contentArray ) { - if ( details.y === undefined ) { continue; } - scriptletHostnameToIdMap(details.y, id, hostnamesMap); - } - const argsList = argsMap2List(argsMap, hostnamesMap); - const entitiesMap = new Map(); - for ( const [ hn, details ] of hostnamesMap ) { - if ( hn.endsWith('.*') === false ) { continue; } - hostnamesMap.delete(hn); - entitiesMap.set(hn.slice(0, -2), details); - } - - // Extract exceptions from argsList, simplify argsList entries - const exceptionsMap = new Map(); - for ( let i = 0; i < argsList.length; i++ ) { - const details = argsList[i]; - if ( details.n ) { - for ( const hn of details.n ) { - if ( exceptionsMap.has(hn) === false ) { - exceptionsMap.set(hn, []); - } - exceptionsMap.get(hn).push(i); - } - } - argsList[i] = details.a; - } - - const originalScriptletMap = await loadAllSourceScriptlets(); - let patchedScriptlet = originalScriptletMap.get('css-declarative').replace( - '$rulesetId$', - assetDetails.id - ); - patchedScriptlet = safeReplace(patchedScriptlet, - /\bself\.\$argsList\$/, - `${JSON.stringify(argsList, scriptletJsonReplacer)}` - ); - patchedScriptlet = safeReplace(patchedScriptlet, - /\bself\.\$hostnamesMap\$/, - `${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}` - ); - patchedScriptlet = safeReplace(patchedScriptlet, - /\bself\.\$entitiesMap\$/, - `${JSON.stringify(entitiesMap, scriptletJsonReplacer)}` - ); - patchedScriptlet = safeReplace(patchedScriptlet, - /\bself\.\$exceptionsMap\$/, - `${JSON.stringify(exceptionsMap, scriptletJsonReplacer)}` - ); - writeFile(`${scriptletDir}/declarative/${assetDetails.id}.js`, patchedScriptlet); - - if ( contentArray.length !== 0 ) { - log(`CSS-declarative: ${declaratives.size} distinct filters`); - log(`\tCombined into ${hostnamesMap.size} distinct hostnames`); - log(`\tCombined into ${entitiesMap.size} distinct entities`); } - return hostnamesMap.size + entitiesMap.size; + return hostnamesMap.size; } /******************************************************************************/ @@ -1037,11 +1008,8 @@ if ( mapin === undefined ) { return 0; } if ( mapin.size === 0 ) { return 0; } - // Distinguish declarative-compiled-as-procedural from actual procedural. const procedurals = new Map(); mapin.forEach((details, jsonSelector) => { - const selector = JSON.parse(jsonSelector); - if ( selector.cssable ) { return; } procedurals.set(jsonSelector, details); }); if ( procedurals.size === 0 ) { return 0; } @@ -1052,39 +1020,29 @@ const argsMap = contentArray.map(entry => [ entry[0], - { - a: entry[1].a, - n: entry[1].n, - } + entry[1].a, ]); const hostnamesMap = new Map(); + let hasEntities = false; for ( const [ id, details ] of contentArray ) { - if ( details.y === undefined ) { continue; } - scriptletHostnameToIdMap(details.y, id, hostnamesMap); - } - const argsList = argsMap2List(argsMap, hostnamesMap); - const entitiesMap = new Map(); - for ( const [ hn, details ] of hostnamesMap ) { - if ( hn.endsWith('.*') === false ) { continue; } - hostnamesMap.delete(hn); - entitiesMap.set(hn.slice(0, -2), details); - } - - // Extract exceptions from argsList, simplify argsList entries - const exceptionsMap = new Map(); - for ( let i = 0; i < argsList.length; i++ ) { - const details = argsList[i]; + if ( details.y ) { + scriptletHostnameToIdMap(details.y, id, hostnamesMap); + hasEntities ||= details.y.some(a => a.endsWith('.*')); + } if ( details.n ) { - for ( const hn of details.n ) { - if ( exceptionsMap.has(hn) === false ) { - exceptionsMap.set(hn, []); - } - exceptionsMap.get(hn).push(i); - } + scriptletHostnameToIdMap(details.n.map(a => `~${a}`), id, hostnamesMap); + hasEntities ||= details.n.some(a => a.endsWith('.*')); } - argsList[i] = details.a; } - + const { argsList, argsSeqs } = argsMap2List(argsMap, hostnamesMap); + const argsListAfter = []; + for ( const a of argsList ) { + const aAfter = []; + for ( let b of a ) { + aAfter.push(JSON.parse(b)); + } + argsListAfter.push(JSON.stringify(aAfter)); + } const originalScriptletMap = await loadAllSourceScriptlets(); let patchedScriptlet = originalScriptletMap.get('css-procedural').replace( '$rulesetId$', @@ -1092,29 +1050,28 @@ ); patchedScriptlet = safeReplace(patchedScriptlet, /\bself\.\$argsList\$/, - `${JSON.stringify(argsList, scriptletJsonReplacer)}` + `${JSON.stringify(argsListAfter, scriptletJsonReplacer)}` ); patchedScriptlet = safeReplace(patchedScriptlet, - /\bself\.\$hostnamesMap\$/, - `${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}` + /\bself\.\$argsSeqs\$/, + `${JSON.stringify(argsSeqs, scriptletJsonReplacer)}` ); patchedScriptlet = safeReplace(patchedScriptlet, - /\bself\.\$entitiesMap\$/, - `${JSON.stringify(entitiesMap, scriptletJsonReplacer)}` + /\bself\.\$hostnamesMap\$/, + `${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}` ); patchedScriptlet = safeReplace(patchedScriptlet, - /\bself\.\$exceptionsMap\$/, - `${JSON.stringify(exceptionsMap, scriptletJsonReplacer)}` + 'self.$hasEntities$', + JSON.stringify(hasEntities) ); writeFile(`${scriptletDir}/procedural/${assetDetails.id}.js`, patchedScriptlet); if ( contentArray.length !== 0 ) { log(`Procedural-related distinct filters: ${procedurals.size} distinct combined selectors`); log(`\tCombined into ${hostnamesMap.size} distinct hostnames`); - log(`\tCombined into ${entitiesMap.size} distinct entities`); } - return hostnamesMap.size + entitiesMap.size; + return hostnamesMap.size; } /******************************************************************************/ @@ -1126,7 +1083,7 @@ makeScriptlet.init(); for ( const details of mapin.values() ) { - makeScriptlet.compile(details); + makeScriptlet.compile(assetDetails, details); } const stats = await makeScriptlet.commit( assetDetails.id, @@ -1148,6 +1105,9 @@ if ( assetDetails.text === undefined && assetDetails.urls.length !== 0 ) { const text = await fetchList(assetDetails); + if ( text === undefined ) { + process.exit(1); + } assetDetails.text = text; } else { assetDetails.text = ''; @@ -1182,8 +1142,12 @@ const results = await dnrRulesetFromRawLists( [ { name: assetDetails.id, text: assetDetails.text } ], - { env, extensionPaths, secret } + { env, extensionPaths, secret, networkBad } ); + networkBad = results.networkBad; + + // Release memory used by filter list content + assetDetails.text = undefined; const netStats = await processNetworkFilters( assetDetails, @@ -1214,34 +1178,42 @@ log(rejectedCosmetic.map(line => `\t${line}`).join('\n'), true); } + const genericDetailsForRuleset = {}; if ( Array.isArray(results.network.generichideExclusions) && results.network.generichideExclusions.length !== 0 ) { - genericDetails.set( - assetDetails.id, - results.network.generichideExclusions.filter(hn => hn.endsWith('.*') === false).sort() - ); + genericDetailsForRuleset.unhide = results.network.generichideExclusions + .filter(hn => hn.endsWith('.*') === false) + .sort(); + } + if ( + Array.isArray(results.network.generichideInclusions) && + results.network.generichideInclusions.length !== 0 + ) { + genericDetailsForRuleset.hide = results.network.generichideInclusions + .filter(hn => hn.endsWith('.*') === false) + .sort(); + } + if ( genericDetailsForRuleset.unhide || genericDetailsForRuleset.hide ) { + genericDetails.set(assetDetails.id, genericDetailsForRuleset); } const genericCosmeticStats = await processGenericCosmeticFilters( assetDetails, - results.genericCosmetic, - results.genericCosmeticExceptions + results.genericCosmeticFilters, + results.genericCosmeticExceptions, + declarativeCosmetic ); const genericHighCosmeticStats = await processGenericHighCosmeticFilters( assetDetails, - results.genericHighCosmetic, - results.genericCosmeticExceptions + results.genericCosmeticFilters, + results.genericCosmeticExceptions, ); const specificCosmeticStats = await processCosmeticFilters( assetDetails, declarativeCosmetic ); - const declarativeStats = await processDeclarativeCosmeticFilters( - assetDetails, - proceduralCosmetic - ); const proceduralStats = await processProceduralCosmeticFilters( assetDetails, proceduralCosmetic @@ -1281,7 +1253,6 @@ generic: genericCosmeticStats, generichigh: genericHighCosmeticStats, specific: specificCosmeticStats, - declarative: declarativeStats, procedural: proceduralStats, }, scriptlets: scriptletStats, @@ -1306,229 +1277,33 @@ const dayPart = now.getUTCDate(); const hourPart = Math.floor(now.getUTCHours()); const minutePart = Math.floor(now.getUTCMinutes()); - version = `${yearPart}.${monthPart}.${dayPart}.${hourPart * 60 + minutePart}`; + version = `${yearPart}.${monthPart*100+dayPart}.${hourPart*100+minutePart}`; } - log(`Version: ${version}`); + log(`Version: ${version}`, false); - // Get assets.json content - const assets = await fs.readFile( - `./assets.dev.json`, - { encoding: 'utf8' } - ).then(text => + // Get list of rulesets + const rulesets = await fs.readFile('rulesets.json', { + encoding: 'utf8' + }).then(text => JSON.parse(text) ); - // Assemble all default lists as the default ruleset - await rulesetFromURLs({ - id: 'default', - name: 'Ads, trackers, miners, and more' , - enabled: true, - urls: [ - 'https://ublockorigin.github.io/uAssets/filters/filters.min.txt', - 'https://ublockorigin.github.io/uAssets/filters/privacy.min.txt', - 'https://ublockorigin.github.io/uAssets/filters/unbreak.min.txt', - 'https://ublockorigin.github.io/uAssets/filters/quick-fixes.min.txt', - 'https://ublockorigin.github.io/uAssets/filters/ubol-filters.txt', - 'https://ublockorigin.github.io/uAssets/thirdparties/easylist.txt', - 'https://ublockorigin.github.io/uAssets/thirdparties/easyprivacy.txt', - 'https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=1&mimetype=plaintext', - ], - dnrURL: 'https://ublockorigin.github.io/uAssets/dnr/default.json', - homeURL: 'https://github.com/uBlockOrigin/uAssets', - filters: [ - ], - }); - - await rulesetFromURLs({ - id: 'badware', - name: 'Badware risks' , - group: 'malware', - enabled: true, - urls: [ - 'https://ublockorigin.github.io/uAssets/filters/badware.min.txt', - ], - homeURL: 'https://github.com/uBlockOrigin/uAssets', - filters: [ - ], - }); - - // Handpicked rulesets from assets.json - const handpicked = [ - 'block-lan', - 'dpollock-0', - 'adguard-spyware-url', - ]; - for ( const id of handpicked ) { - const asset = assets[id]; - if ( asset.content !== 'filters' ) { continue; } - const contentURL = Array.isArray(asset.contentURL) - ? asset.contentURL[0] - : asset.contentURL; - await rulesetFromURLs({ - id: id.toLowerCase(), - name: asset.title, - enabled: false, - urls: [ contentURL ], - homeURL: asset.supportURL, - }); + for ( const ruleset of rulesets ) { + if ( ruleset.excludedPlatforms?.includes(platform) ) { continue; } + await rulesetFromURLs(ruleset); } - // Handpicked annoyance rulesets from assets.json - await rulesetFromURLs({ - id: 'annoyances-cookies', - name: 'EasyList/uBO – Cookie Notices', - group: 'annoyances', - enabled: false, - urls: [ - 'https://ublockorigin.github.io/uAssets/thirdparties/easylist-cookies.txt', - 'https://ublockorigin.github.io/uAssets/filters/annoyances-cookies.txt', - ], - homeURL: 'https://github.com/easylist/easylist#fanboy-lists', - }); - await rulesetFromURLs({ - id: 'annoyances-overlays', - name: 'EasyList/uBO – Overlay Notices', - group: 'annoyances', - enabled: false, - urls: [ - 'https://ublockorigin.github.io/uAssets/thirdparties/easylist-newsletters.txt', - 'https://ublockorigin.github.io/uAssets/filters/annoyances-others.txt', - ], - homeURL: 'https://github.com/easylist/easylist#fanboy-lists', - }); - await rulesetFromURLs({ - id: 'annoyances-social', - name: 'EasyList – Social Widgets', - group: 'annoyances', - enabled: false, - urls: [ - 'https://ublockorigin.github.io/uAssets/thirdparties/easylist-social.txt', - ], - homeURL: 'https://github.com/easylist/easylist#fanboy-lists', - }); - await rulesetFromURLs({ - id: 'annoyances-widgets', - name: 'EasyList – Chat Widgets', - group: 'annoyances', - enabled: false, - urls: [ - 'https://ublockorigin.github.io/uAssets/thirdparties/easylist-chat.txt', - ], - homeURL: 'https://github.com/easylist/easylist#fanboy-lists', - }); - await rulesetFromURLs({ - id: 'annoyances-others', - name: 'EasyList – Other Annoyances', - group: 'annoyances', - enabled: false, - urls: [ - 'https://ublockorigin.github.io/uAssets/thirdparties/easylist-annoyances.txt' - ], - homeURL: 'https://github.com/easylist/easylist#fanboy-lists', - }); - - // Handpicked rulesets from abroad - await rulesetFromURLs({ - id: 'urlhaus-full', - name: 'Malicious URL Blocklist', - group: 'malware', - enabled: true, - urls: [ - 'https://malware-filter.gitlab.io/malware-filter/urlhaus-filter-hosts.txt', - ], - filters: [ - ], - homeURL: 'https://gitlab.com/malware-filter/urlhaus-filter', - }); - await rulesetFromURLs({ - id: 'openphish-domains', - name: 'OpenPhish Domain Blocklist', - group: 'malware', - enabled: true, - urls: [ - 'https://raw.githubusercontent.com/stephenhawk8054/openphish-adblock/refs/heads/main/filters_init_domains.txt', - ], - filters: [ - ], - homeURL: 'https://github.com/stephenhawk8054/openphish-adblock', - }); + logProgress(''); - await rulesetFromURLs({ - id: 'stevenblack-hosts', - name: 'Steven Black’s Unified Hosts (adware + malware)', - enabled: false, - urls: [ 'https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts' ], - homeURL: 'https://github.com/StevenBlack/hosts#readme', - }); - - // Regional rulesets - const excludedLists = [ - 'ara-0', - 'EST-0', - ]; - // Merge lists which have same target languages - const langToListsMap = new Map(); - for ( const [ id, asset ] of Object.entries(assets) ) { - if ( asset.content !== 'filters' ) { continue; } - if ( asset.off !== true ) { continue; } - if ( asset.group !== 'regions' ) { continue; } - if ( excludedLists.includes(id) ) { continue; } - // Not all "regions" lists have a set language - const bundleId = asset.lang || - createHash('sha256').update(randomBytes(16)).digest('hex').slice(0,16); - let ids = langToListsMap.get(bundleId); - if ( ids === undefined ) { - langToListsMap.set(bundleId, ids = []); - } - ids.push(id); - } - for ( const ids of langToListsMap.values() ) { - const urls = []; - for ( const id of ids ) { - const asset = assets[id]; - const contentURL = Array.isArray(asset.contentURL) - ? asset.contentURL[0] - : asset.contentURL; - urls.push(contentURL); - } - const id = ids[0]; - const asset = assets[id]; - const rulesetDetails = { - id: id.toLowerCase(), - group: 'regions', - parent: asset.parent, - lang: asset.lang, - name: asset.title, - tags: asset.tags, - enabled: false, - urls, - homeURL: asset.supportURL, - }; - await rulesetFromURLs(rulesetDetails); - } - - await rulesetFromURLs({ - id: 'est-0', - group: 'regions', - lang: 'et', - name: '🇪🇪ee: Eesti saitidele kohandatud filter', - enabled: false, - urls: [ 'https://ubol-et.adblock.ee/list.txt' ], - homeURL: 'https://github.com/sander85/uBOL-et', - }); - - writeFile( - `${rulesetDir}/ruleset-details.json`, + writeFile(`${rulesetDir}/ruleset-details.json`, `${JSON.stringify(rulesetDetails, null, 1)}\n` ); - writeFile( - `${rulesetDir}/scriptlet-details.json`, + writeFile(`${rulesetDir}/scriptlet-details.json`, `${JSON.stringify(scriptletStats, jsonSetMapReplacer, 1)}\n` ); - writeFile( - `${rulesetDir}/generic-details.json`, + writeFile(`${rulesetDir}/generic-details.json`, `${JSON.stringify(genericDetails, jsonSetMapReplacer, 1)}\n` ); @@ -1552,10 +1327,10 @@ // Patch web_accessible_resources key manifest.web_accessible_resources = manifest.web_accessible_resources || []; const web_accessible_resources = { - resources: Array.from(requiredRedirectResources).map(path => `/${path}`), + resources: Array.from(requiredRedirectResources).map(path => `${path}`), matches: [ '' ], }; - if ( platform === 'chromium' ) { + if ( env.includes('chromium') && env.includes('safari') === false ) { web_accessible_resources.use_dynamic_url = true; } manifest.web_accessible_resources.push(web_accessible_resources); @@ -1563,8 +1338,7 @@ // Patch manifest version property manifest.version = version; // Commit changes - await fs.writeFile( - `${outputDir}/manifest.json`, + await fs.writeFile(`${outputDir}/manifest.json`, JSON.stringify(manifest, null, 2) + '\n' ); diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/make-scriptlets.js ublock-origin-1.67.0+dfsg/platform/mv3/make-scriptlets.js --- ublock-origin-1.62.0+dfsg/platform/mv3/make-scriptlets.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/make-scriptlets.js 2025-10-25 19:32:51.000000000 +0000 @@ -75,7 +75,7 @@ /******************************************************************************/ -export function compile(details) { +export function compile(assetDetails, details) { if ( details.args[0].endsWith('.js') === false ) { details.args[0] += '.js'; } @@ -85,8 +85,9 @@ const scriptletToken = details.args[0]; const resourceEntry = resourceDetails.get(scriptletToken); if ( resourceEntry === undefined ) { return; } + const argsToken = JSON.stringify(details.args.slice(1)); if ( resourceEntry.requiresTrust && details.trustedSource !== true ) { - console.log(`Rejecting ${scriptletToken}: source is not trusted`); + console.log(`Rejecting +js(${scriptletToken},${argsToken.slice(1,-1)}): ${assetDetails.id} is not trusted`); return; } if ( scriptletFiles.has(scriptletToken) === false ) { @@ -96,36 +97,34 @@ world: resourceEntry.world, args: new Map(), hostnames: new Map(), - entities: new Map(), exceptions: new Map(), + hasEntities: false, + hasAncestors: false, matches: new Set(), }); } const scriptletDetails = scriptletFiles.get(scriptletToken); - const argsToken = JSON.stringify(details.args.slice(1)); if ( scriptletDetails.args.has(argsToken) === false ) { scriptletDetails.args.set(argsToken, scriptletDetails.args.size); } const iArgs = scriptletDetails.args.get(argsToken); if ( details.matches ) { for ( const hn of details.matches ) { - if ( hn.endsWith('.*') ) { + const isEntity = hn.endsWith('.*') || hn.endsWith('.*>>'); + scriptletDetails.hasEntities ||= isEntity; + const isAncestor = hn.endsWith('>>') + scriptletDetails.hasAncestors ||= isAncestor; + if ( isEntity || isAncestor ) { scriptletDetails.matches.clear(); scriptletDetails.matches.add('*'); - const entity = hn.slice(0, -2); - if ( scriptletDetails.entities.has(entity) === false ) { - scriptletDetails.entities.set(entity, new Set()); - } - scriptletDetails.entities.get(entity).add(iArgs); - } else { - if ( scriptletDetails.matches.has('*') === false ) { - scriptletDetails.matches.add(hn); - } - if ( scriptletDetails.hostnames.has(hn) === false ) { - scriptletDetails.hostnames.set(hn, new Set()); - } - scriptletDetails.hostnames.get(hn).add(iArgs); } + if ( scriptletDetails.matches.has('*') === false ) { + scriptletDetails.matches.add(hn); + } + if ( scriptletDetails.hostnames.has(hn) === false ) { + scriptletDetails.hostnames.set(hn, new Set()); + } + scriptletDetails.hostnames.get(hn).add(iArgs); } } else { scriptletDetails.matches.add('*'); @@ -163,7 +162,6 @@ ); content = safeReplace(content, /\$rulesetId\$/, rulesetId, 0); content = safeReplace(content, /\$scriptletName\$/, details.name, 0); - content = safeReplace(content, '$world$', details.world); content = safeReplace(content, 'self.$argsList$', JSON.stringify(Array.from(details.args.keys()).map(a => JSON.parse(a))) @@ -173,15 +171,24 @@ JSON.stringify(patchHnMap(details.hostnames)) ); content = safeReplace(content, - 'self.$entitiesMap$', - JSON.stringify(patchHnMap(details.entities)) + 'self.$hasEntities$', + JSON.stringify(details.hasEntities) + ); + content = safeReplace(content, + 'self.$hasAncestors$', + JSON.stringify(details.hasAncestors) ); content = safeReplace(content, 'self.$exceptionsMap$', JSON.stringify(Array.from(details.exceptions)) ); writeFn(`${path}/${rulesetId}.${name}`, content); - scriptletStats.push([ name.slice(0, -3), Array.from(details.matches).sort() ]); + scriptletStats.push([ + name.slice(0, -3), { + hostnames: Array.from(details.matches).sort(), + world: details.world, + } + ]); } return scriptletStats; } diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/rulesets.json ublock-origin-1.67.0+dfsg/platform/mv3/rulesets.json --- ublock-origin-1.62.0+dfsg/platform/mv3/rulesets.json 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/rulesets.json 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,636 @@ +[ + { + "id": "ublock-filters", + "name": "uBlock filters – Ads, trackers, and more", + "group": "default", + "enabled": true, + "trusted": true, + "urls": [ + "https://ublockorigin.github.io/uAssets/filters/quick-fixes.min.txt", + "https://ublockorigin.github.io/uAssets/filters/unbreak.min.txt", + "https://ublockorigin.github.io/uAssets/filters/filters.min.txt", + "https://ublockorigin.github.io/uAssets/filters/privacy.min.txt", + "https://ublockorigin.github.io/uAssets/filters/ubol-filters.txt" + ], + "homeURL": "https://github.com/uBlockOrigin/uAssets" + }, + { + "id": "easylist", + "name": "EasyList", + "group": "default", + "enabled": true, + "urls": [ + "https://ublockorigin.github.io/uAssets/thirdparties/easylist.txt" + ], + "homeURL": "https://easylist.to/" + }, + { + "id": "easyprivacy", + "name": "EasyPrivacy", + "group": "default", + "enabled": true, + "urls": [ + "https://ublockorigin.github.io/uAssets/thirdparties/easyprivacy.txt" + ], + "homeURL": "https://easylist.to/" + }, + { + "id": "pgl", + "name": "Peter Lowe – Ads, trackers, and more", + "group": "default", + "enabled": true, + "urls": [ + "https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=1&mimetype=plaintext" + ], + "homeURL": "https://pgl.yoyo.org/adservers/" + }, + { + "id": "ublock-badware", + "name": "uBlock filters – Badware risks", + "group": "malware", + "enabled": true, + "trusted": true, + "urls": [ + "https://ublockorigin.github.io/uAssets/filters/badware.min.txt" + ], + "homeURL": "https://github.com/uBlockOrigin/uAssets" + }, + { + "id": "urlhaus-full", + "name": "Malicious URL Blocklist", + "group": "malware", + "enabled": true, + "excludedPlatforms": [ "safari" ], + "urls": [ + "https://malware-filter.gitlab.io/malware-filter/urlhaus-filter-hosts.txt" + ], + "homeURL": "https://gitlab.com/malware-filter/urlhaus-filter" + }, + { + "id": "adguard-mobile", + "name": "AdGuard/uBO – Mobile Ads", + "group": "ads", + "enabled": false, + "tags": "mobile", + "urls": [ + "https://ublockorigin.github.io/uAssets/filters/filters-mobile.txt", + "https://filters.adtidy.org/extension/ublock/filters/11.txt" + ], + "homeURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + { + "id": "block-lan", + "name": "Block Outsider Intrusion into LAN", + "group": "privacy", + "enabled": false, + "urls": [ + "https://ublockorigin.github.io/uAssets/filters/lan-block.txt" + ], + "homeURL": "https://github.com/uBlockOrigin/uAssets" + }, + { + "id": "dpollock-0", + "name": "Dan Pollock’s hosts file", + "enabled": false, + "excludedPlatforms": [ "safari" ], + "urls": [ + "https://someonewhocares.org/hosts/hosts" + ], + "homeURL": "https://someonewhocares.org/hosts/" + }, + { + "id": "adguard-spyware-url", + "name": "AdGuard URL Tracking Protection", + "group": "privacy", + "enabled": false, + "excludedPlatforms": [ "safari" ], + "urls": [ + "https://filters.adtidy.org/extension/ublock/filters/17.txt" + ], + "homeURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + { + "id": "annoyances-cookies", + "name": "EasyList/uBO – Cookie Notices", + "group": "annoyances", + "enabled": false, + "urls": [ + "https://ublockorigin.github.io/uAssets/thirdparties/easylist-cookies.txt", + "https://ublockorigin.github.io/uAssets/filters/annoyances-cookies.txt" + ], + "homeURL": "https://github.com/easylist/easylist#fanboy-lists" + }, + { + "id": "annoyances-overlays", + "name": "EasyList/uBO – Overlay Notices", + "group": "annoyances", + "enabled": false, + "urls": [ + "https://ublockorigin.github.io/uAssets/thirdparties/easylist-newsletters.txt", + "https://ublockorigin.github.io/uAssets/filters/annoyances-others.txt" + ], + "homeURL": "https://github.com/easylist/easylist#fanboy-lists" + }, + { + "id": "annoyances-social", + "name": "EasyList – Social Widgets", + "group": "annoyances", + "enabled": false, + "urls": [ + "https://ublockorigin.github.io/uAssets/thirdparties/easylist-social.txt" + ], + "homeURL": "https://github.com/easylist/easylist#fanboy-lists" + }, + { + "id": "annoyances-widgets", + "name": "EasyList – Chat Widgets", + "group": "annoyances", + "enabled": false, + "urls": [ + "https://ublockorigin.github.io/uAssets/thirdparties/easylist-chat.txt" + ], + "homeURL": "https://github.com/easylist/easylist#fanboy-lists" + }, + { + "id": "annoyances-others", + "name": "EasyList – Other Annoyances", + "group": "annoyances", + "enabled": false, + "urls": [ + "https://ublockorigin.github.io/uAssets/thirdparties/easylist-annoyances.txt" + ], + "homeURL": "https://github.com/easylist/easylist#fanboy-lists" + }, + { + "id": "annoyances-notifications", + "name": "EasyList – Notifications", + "group": "annoyances", + "enabled": false, + "urls": [ + "https://ublockorigin.github.io/uAssets/thirdparties/easylist-notifications.txt" + ], + "homeURL": "https://github.com/easylist/easylist#fanboy-lists" + }, + { + "id": "ublock-experimental", + "name": "uBlock filters – Experimental", + "enabled": false, + "trusted": true, + "urls": [ + "https://ublockorigin.github.io/uAssets/filters/experimental.min.txt" + ], + "homeURL": "https://github.com/uBlockOrigin/uAssets" + }, + { + "id": "stevenblack-hosts", + "name": "Steven Black’s Unified Hosts (adware + malware)", + "enabled": false, + "excludedPlatforms": [ "safari" ], + "urls": [ + "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" + ], + "homeURL": "https://github.com/StevenBlack/hosts#readme" + }, + { + "id": "ubol-tests", + "name": "uBO Lite Test Filters", + "enabled": false, + "trusted": true, + "urls": [ + "https://ublockorigin.github.io/uBOL-home/tests/test-filters.txt" + ], + "homeURL": "https://ublockorigin.github.io/uBOL-home/tests/test-filters.html" + }, + { + "id": "alb-0", + "group": "regions", + "lang": "sq", + "name": "🇦🇱al 🇽🇰xk: Adblock List for Albania", + "tags": "ads albania shqipja", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/AnXh3L0/blocklist/master/albanian-easylist-addition/Albania.txt" + ], + "homeURL": "https://github.com/AnXh3L0/blocklist" + }, + { + "id": "bgr-0", + "group": "regions", + "lang": "bg mk", + "name": "🇧🇬bg: Bulgarian Adblock list", + "tags": "ads bulgarian България macedonian Македонија", + "enabled": false, + "urls": [ + "https://stanev.org/abp/adblock_bg.txt" + ], + "homeURL": "https://stanev.org/abp/" + }, + { + "id": "chn-0", + "group": "regions", + "lang": "ug zh", + "name": "🇨🇳cn 🇹🇼tw: AdGuard Chinese (中文)", + "tags": "ads chinese 中文", + "enabled": false, + "urls": [ + "https://filters.adtidy.org/extension/ublock/filters/224.txt" + ], + "homeURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + { + "id": "cze-0", + "group": "regions", + "lang": "cs sk", + "name": "🇨🇿cz 🇸🇰sk: EasyList Czech and Slovak", + "tags": "ads czech česká slovak slovenská", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/tomasko126/easylistczechandslovak/master/filters.txt" + ], + "homeURL": "https://github.com/tomasko126/easylistczechandslovak" + }, + { + "id": "deu-0", + "group": "regions", + "lang": "de dsb hsb lb rm", + "name": "🇩🇪de 🇨🇭ch 🇦🇹at: EasyList Germany", + "tags": "ads german deutschland luxembourgish lëtzebuerg romansh", + "enabled": false, + "urls": [ + "https://easylist.to/easylistgermany/easylistgermany.txt" + ], + "homeURL": "https://forums.lanik.us/viewforum.php?f=90" + }, + { + "id": "est-0", + "group": "regions", + "lang": "et", + "name": "🇪🇪ee: Eesti saitidele kohandatud filter", + "enabled": false, + "urls": [ + "https://ubol-et.adblock.ee/list.txt" + ], + "homeURL": "https://github.com/sander85/uBOL-et" + }, + { + "id": "fin-0", + "group": "regions", + "lang": "fi", + "name": "🇫🇮fi: Adblock List for Finland", + "tags": "ads finnish", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/finnish-easylist-addition/finnish-easylist-addition/gh-pages/Finland_adb.txt" + ], + "homeURL": "https://github.com/finnish-easylist-addition/finnish-easylist-addition" + }, + { + "id": "fra-0", + "group": "regions", + "lang": "ar br ff fr lb oc son", + "name": "🇫🇷fr 🇨🇦ca: AdGuard Français", + "tags": "ads french", + "enabled": false, + "urls": [ + "https://filters.adtidy.org/extension/ublock/filters/16.txt" + ], + "homeURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + { + "id": "grc-0", + "group": "regions", + "lang": "el", + "name": "🇬🇷gr 🇨🇾cy: Greek AdBlock Filter", + "tags": "ads greek", + "enabled": false, + "urls": [ + "https://www.void.gr/kargig/void-gr-filters.txt" + ], + "homeURL": "https://github.com/kargig/greek-adblockplus-filter" + }, + { + "id": "hrv-0", + "group": "regions", + "lang": "bs hr sr", + "name": "🇭🇷hr 🇷🇸rs: Dandelion Sprout's Serbo-Croatian filters", + "tags": "ads croatian serbian bosnian", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/DandelionSprout/adfilt/master/SerboCroatianList.txt" + ], + "homeURL": "https://github.com/DandelionSprout/adfilt#readme" + }, + { + "id": "hun-0", + "group": "regions", + "lang": "hu", + "name": "🇭🇺hu: hufilter", + "tags": "ads hungarian", + "enabled": false, + "urls": [ + "https://cdn.jsdelivr.net/gh/hufilter/hufilter@gh-pages/hufilter-ublock.txt" + ], + "homeURL": "https://github.com/hufilter/hufilter" + }, + { + "id": "idn-0", + "group": "regions", + "lang": "id ms", + "name": "🇮🇩id 🇲🇾my: ABPindo", + "tags": "ads indonesian malay", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/ABPindo/indonesianadblockrules/master/subscriptions/abpindo.txt" + ], + "homeURL": "https://github.com/ABPindo/indonesianadblockrules" + }, + { + "id": "ind-0", + "group": "regions", + "lang": "as bn gu hi kn ml mr ne pa si ta te", + "name": "🇮🇳in 🇱🇰lk 🇳🇵np: IndianList", + "tags": "ads assamese bengali gujarati hindi kannada malayalam marathi nepali punjabi sinhala tamil telugu", + "enabled": false, + "urls": [ + "https://easylist-downloads.adblockplus.org/indianlist.txt" + ], + "homeURL": "https://github.com/mediumkreation/IndianList" + }, + { + "id": "irn-0", + "group": "regions", + "lang": "fa ps tg", + "name": "🇮🇷ir: PersianBlocker", + "tags": "ads af ir persian pashto tajik tj", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/MasterKia/PersianBlocker/main/PersianBlocker.txt" + ], + "homeURL": "https://github.com/MasterKia/PersianBlocker" + }, + { + "id": "isl-0", + "group": "regions", + "lang": "is", + "name": "🇮🇸is: Icelandic ABP List", + "tags": "ads icelandic", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/brave/adblock-lists/master/custom/is.txt" + ], + "homeURL": "https://github.com/brave/adblock-lists/issues" + }, + { + "id": "isr-0", + "group": "regions", + "lang": "he", + "name": "🇮🇱il: EasyList Hebrew", + "tags": "ads hebrew", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/easylist/EasyListHebrew/master/EasyListHebrew.txt" + ], + "homeURL": "https://github.com/easylist/EasyListHebrew" + }, + { + "id": "ita-0", + "group": "regions", + "lang": "it lij", + "name": "🇮🇹it: EasyList Italy", + "tags": "ads italian", + "enabled": false, + "urls": [ + "https://easylist-downloads.adblockplus.org/easylistitaly.txt" + ], + "homeURL": "https://forums.lanik.us/viewforum.php?f=96" + }, + { + "id": "jpn-1", + "group": "regions", + "lang": "ja", + "name": "🇯🇵jp: AdGuard Japanese", + "tags": "ads japanese 日本語", + "enabled": false, + "urls": [ + "https://filters.adtidy.org/extension/ublock/filters/7.txt" + ], + "homeURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + { + "id": "kor-1", + "group": "regions", + "lang": "ko", + "name": "🇰🇷kr: List-KR", + "tags": "ads korean 한국어", + "enabled": false, + "urls": [ + "https://cdn.jsdelivr.net/gh/List-KR/List-KR@latest/filter-uBlockOrigin.txt" + ], + "homeURL": "https://github.com/List-KR/List-KR#readme" + }, + { + "id": "ltu-0", + "group": "regions", + "lang": "lt", + "name": "🇱🇹lt: EasyList Lithuania", + "tags": "ads lithuanian", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/EasyList-Lithuania/easylist_lithuania/master/easylistlithuania.txt" + ], + "homeURL": "https://github.com/EasyList-Lithuania/easylist_lithuania" + }, + { + "id": "lva-0", + "group": "regions", + "lang": "lv", + "name": "🇱🇻lv: Latvian List", + "tags": "ads latvian", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/Latvian-List/adblock-latvian/master/lists/latvian-list.txt" + ], + "homeURL": "https://github.com/Latvian-List/adblock-latvian" + }, + { + "id": "mkd-0", + "group": "regions", + "lang": "mk", + "name": "🇲🇰mk: Macedonian adBlock Filters", + "tags": "ads macedonian", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/DeepSpaceHarbor/Macedonian-adBlock-Filters/master/Filters" + ], + "homeURL": "https://github.com/DeepSpaceHarbor/Macedonian-adBlock-Filters" + }, + { + "id": "nld-0", + "group": "regions", + "lang": "af fy nl", + "name": "🇳🇱nl 🇧🇪be: AdGuard Dutch", + "tags": "ads afrikaans be belgië frisian dutch flemish nederlands netherlands nl sr suriname za", + "enabled": false, + "urls": [ + "https://filters.adtidy.org/extension/ublock/filters/8.txt" + ], + "homeURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + { + "id": "nor-0", + "group": "regions", + "lang": "nb nn no da is", + "name": "🇳🇴no 🇩🇰dk 🇮🇸is: Dandelion Sprouts nordiske filtre", + "tags": "ads norwegian danish icelandic", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/DandelionSprout/adfilt/master/NorwegianList.txt" + ], + "homeURL": "https://github.com/DandelionSprout/adfilt" + }, + { + "id": "pol-0", + "group": "regions", + "lang": "szl pl _", + "name": "🇵🇱pl: Oficjalne Polskie Filtry do uBlocka Origin", + "tags": "ads polish polski", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/MajkiIT/polish-ads-filter/master/polish-adblock-filters/adblock.txt" + ], + "homeURL": "https://github.com/MajkiIT/polish-ads-filter" + }, + { + "id": "rou-1", + "group": "regions", + "lang": "ro", + "name": "🇷🇴ro 🇲🇩md: Romanian Ad (ROad) Block List Light", + "tags": "ads romanian română moldavian moldovenească молдовеняскэ", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/tcptomato/ROad-Block/master/road-block-filters-light.txt" + ], + "homeURL": "https://github.com/tcptomato/ROad-Block" + }, + { + "id": "rus-0", + "group": "regions", + "parent": "🇷🇺ru 🇺🇦ua 🇺🇿uz 🇰🇿kz: RU AdList", + "lang": "be kk tt ru uz", + "name": "🇷🇺ru 🇺🇦ua 🇺🇿uz 🇰🇿kz: RU AdList", + "tags": "ads belarusian беларуская kazakh tatar russian русский ukrainian українська uzbek uk", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/easylist/ruadlist/master/RuAdList-uBO.txt" + ], + "homeURL": "https://forums.lanik.us/viewforum.php?f=102" + }, + { + "id": "rus-1", + "group": "regions", + "parent": "🇷🇺ru 🇺🇦ua 🇺🇿uz 🇰🇿kz: RU AdList", + "name": "🇷🇺ru 🇺🇦ua 🇺🇿uz 🇰🇿kz: RU AdList: Counters", + "tags": "ads belarusian беларуская kazakh tatar russian русский ukrainian українська uzbek be kk tt ru uk uz", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/easylist/ruadlist/master/cntblock.txt" + ], + "homeURL": "https://forums.lanik.us/viewforum.php?f=102" + }, + { + "id": "spa-0", + "group": "regions", + "lang": "an ast ca cak es eu gl gn trs quz", + "name": "🇪🇸es 🇦🇷ar 🇲🇽mx 🇨🇴co: EasyList Spanish", + "tags": "ads aragonese basque catalan spanish español galician guarani", + "enabled": false, + "urls": [ + "https://easylist-downloads.adblockplus.org/easylistspanish.txt" + ], + "homeURL": "https://forums.lanik.us/viewforum.php?f=103" + }, + { + "id": "spa-1", + "group": "regions", + "lang": "an ast ca cak es eu gl gn trs pt quz", + "name": "🇪🇸es 🇦🇷ar 🇧🇷br 🇵🇹pt: AdGuard Spanish/Portuguese", + "tags": "ads aragonese basque catalan spanish español galician guarani portuguese português", + "enabled": false, + "urls": [ + "https://filters.adtidy.org/extension/ublock/filters/9.txt" + ], + "homeURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + { + "id": "svn-0", + "group": "regions", + "lang": "sl", + "name": "🇸🇮si: Slovenian List", + "tags": "ads slovenian slovenski", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/betterwebleon/slovenian-list/master/filters.txt" + ], + "homeURL": "https://github.com/betterwebleon/slovenian-list" + }, + { + "id": "swe-1", + "group": "regions", + "lang": "sv", + "name": "🇸🇪se: Frellwit's Swedish Filter", + "tags": "ads swedish svenska", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/lassekongo83/Frellwits-filter-lists/master/Frellwits-Swedish-Filter.txt" + ], + "homeURL": "https://github.com/lassekongo83/Frellwits-filter-lists" + }, + { + "id": "tha-0", + "group": "regions", + "lang": "th", + "name": "🇹🇭th: EasyList Thailand", + "tags": "ads thai ไทย", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/easylist-thailand/easylist-thailand/master/subscription/easylist-thailand.txt" + ], + "homeURL": "https://github.com/easylist-thailand/easylist-thailand" + }, + { + "id": "tur-0", + "group": "regions", + "lang": "tr", + "name": "🇹🇷tr: AdGuard Turkish", + "tags": "ads turkish türkçe", + "enabled": false, + "urls": [ + "https://filters.adtidy.org/extension/ublock/filters/13.txt" + ], + "homeURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + { + "id": "ukr-0", + "group": "regions", + "lang": "uk", + "name": "🇺🇦ua: AdGuard Ukrainian", + "tags": "ads ukraine україна", + "enabled": false, + "urls": [ + "https://filters.adtidy.org/extension/ublock/filters/23.txt" + ], + "homeURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + { + "id": "vie-1", + "group": "regions", + "lang": "vi", + "name": "🇻🇳vn: ABPVN List", + "tags": "ads vietnamese việt", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/abpvn/abpvn/master/filter/abpvn_ublock.txt" + ], + "homeURL": "https://abpvn.com/" + } +] diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/safari/css-api.js ublock-origin-1.67.0+dfsg/platform/mv3/safari/css-api.js --- ublock-origin-1.62.0+dfsg/platform/mv3/safari/css-api.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/safari/css-api.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,46 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +(api => { + if ( typeof api === 'object' ) { return; } + + const inserted = new Set(); + + self.cssAPI = { + insert(css) { + chrome.runtime.sendMessage({ + what: 'insertCSS', + css, + }).catch(( ) => { + }); + inserted.add(css); + }, + }; + + self.addEventListener('pageshow', ( ) => { + chrome.runtime.sendMessage({ + what: 'insertCSS', + css: Array.from(inserted).join('\n'), + }).catch(( ) => { + }); + }); + +})(self.cssAPI); diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/safari/css-user.js ublock-origin-1.67.0+dfsg/platform/mv3/safari/css-user.js --- ublock-origin-1.62.0+dfsg/platform/mv3/safari/css-user.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/safari/css-user.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,59 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2019-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +(async function uBOL_cssUser() { + +/******************************************************************************/ + +const docURL = new URL(document.baseURI); +const details = await chrome.runtime.sendMessage({ + what: 'injectCustomFilters', + hostname: docURL.hostname, +}).catch(( ) => { +}); + +if ( details?.proceduralSelectors?.length ) { + if ( self.ProceduralFiltererAPI ) { + self.customProceduralFiltererAPI = new self.ProceduralFiltererAPI(); + self.customProceduralFiltererAPI.addSelectors( + details.proceduralSelectors.map(a => JSON.parse(a)) + ); + } +} + +if ( details?.plainSelectors?.length ) { + const selectors = details.plainSelectors; + self.addEventListener('pageshow', ( ) => { + chrome.runtime.sendMessage({ + what: 'insertCSS', + css: `${selectors.join(',\n')}{display:none!important;}`, + }).catch(( ) => { + }); + }); +} + +self.customFilters = details; + +/******************************************************************************/ + +})(); + +void 0; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/safari/ext-compat.js ublock-origin-1.67.0+dfsg/platform/mv3/safari/ext-compat.js --- ublock-origin-1.62.0+dfsg/platform/mv3/safari/ext-compat.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/safari/ext-compat.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,223 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2022-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + + +export const webext = self.browser; + +/******************************************************************************/ + +// https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/declarativeNetRequest/ + +const nativeDNR = webext.declarativeNetRequest; + +const isSupportedRule = r => { + if ( r.action.responseHeaders ) { return false; } + const { condition } = r; + if ( condition.tabIds !== undefined ) { return false; } + if ( condition.resourceTypes?.includes('object') ) { + if ( condition.resourceTypes.length === 1 ) { return false; } + const i = condition.resourceTypes.indexOf('object'); + condition.resourceTypes.splice(i, 1); + } + if ( condition.excludedResourceTypes?.includes('object') ) { + const i = condition.excludedResourceTypes.indexOf('object'); + condition.excludedResourceTypes.splice(i, 1); + if ( condition.excludedResourceTypes.length === 0 ) { + delete condition.excludedResourceTypes; + } + } + return true; +}; + +const prepareUpdateRules = optionsBefore => { + const { addRules, removeRuleIds } = optionsBefore; + const addRulesAfter = addRules?.filter(isSupportedRule); + if ( Boolean(addRulesAfter?.length || removeRuleIds?.length) === false ) { return; } + addRulesAfter?.forEach(r => { + if ( r.action?.redirect?.regexSubstitution ) { + if ( r.condition?.requestDomains ) { + r.condition.domains = r.condition.requestDomains; + delete r.condition.requestDomains; + return; + } + } + if ( r.condition?.initiatorDomains ) { + r.condition.domains = r.condition.initiatorDomains; + delete r.condition.initiatorDomains; + } + if ( r.condition?.excludedInitiatorDomains ) { + r.condition.excludedDomains = r.condition.excludedInitiatorDomains; + delete r.condition.excludedInitiatorDomains; + } + }); + const optionsAfter = {}; + if ( addRulesAfter?.length ) { optionsAfter.addRules = addRulesAfter; } + if ( removeRuleIds?.length ) { optionsAfter.removeRuleIds = removeRuleIds; } + return optionsAfter; +}; + +const ruleCompare = (a, b) => a.id - b.id; + +const isSameRules = (a, b) => { + a.sort(ruleCompare); + b.sort(ruleCompare); + return JSON.stringify(a) === JSON.stringify(b); +}; + +/******************************************************************************/ + +export function normalizeDNRRules(rules, ruleIds) { + if ( Array.isArray(rules) === false ) { return rules; } + const selectedRules = Array.isArray(ruleIds) + ? rules.filter(rule => ruleIds.includes(rule.id)) + : rules; + selectedRules.forEach(rule => { + const { condition } = rule; + if ( Array.isArray(condition.domains) ) { + condition.initiatorDomains = condition.domains; + delete condition.domains; + } + if ( Array.isArray(condition.excludedDomains) ) { + condition.excludedInitiatorDomains = condition.excludedDomains; + delete condition.excludedDomains; + } + }); + return selectedRules; +} + +/******************************************************************************/ + +export const dnr = { + DYNAMIC_RULESET_ID: '_dynamic', + MAX_NUMBER_OF_ENABLED_STATIC_RULESETS: nativeDNR.MAX_NUMBER_OF_ENABLED_STATIC_RULESETS, + MAX_NUMBER_OF_REGEX_RULES: nativeDNR.MAX_NUMBER_OF_DYNAMIC_AND_SESSION_RULES, + async getAvailableStaticRuleCount() { + return 150000; + }, + getDynamicRules({ ruleIds } = {}) { + return new Promise(resolve => { + nativeDNR.getDynamicRules(rules => { + if ( Array.isArray(rules) === false ) { return resolve([]); } + return resolve(normalizeDNRRules(rules, ruleIds)); + }); + }); + }, + getEnabledRulesets(...args) { + return nativeDNR.getEnabledRulesets(...args); + }, + getMatchedRules(...args) { + return nativeDNR.getMatchedRules(...args); + }, + getSessionRules({ ruleIds } = {}) { + return new Promise(resolve => { + nativeDNR.getSessionRules(rules => { + if ( Array.isArray(rules) === false ) { return resolve([]); } + return resolve(normalizeDNRRules(rules, ruleIds)); + }); + }); + }, + isRegexSupported(...args) { + return nativeDNR.isRegexSupported(...args); + }, + async updateDynamicRules(optionsBefore) { + const optionsAfter = prepareUpdateRules(optionsBefore); + if ( optionsAfter === undefined ) { return; } + return nativeDNR.updateDynamicRules(optionsAfter); + }, + updateEnabledRulesets(...args) { + return nativeDNR.updateEnabledRulesets(...args); + }, + async updateSessionRules(optionsBefore) { + const optionsAfter = prepareUpdateRules(optionsBefore); + if ( optionsAfter === undefined ) { return; } + return nativeDNR.updateSessionRules(optionsAfter); + }, + async setAllowAllRules(id, allowed, notAllowed, reverse, priority) { + const beforeRules = await this.getDynamicRules({ ruleIds: [ id+0 ] }); + const addRules = []; + if ( reverse || allowed.length || notAllowed.length ) { + const rule0 = { + id: id+0, + action: { type: 'allow' }, + condition: { urlFilter: '*' }, + priority, + }; + if ( allowed.length ) { + rule0.condition.domains = allowed; + } else if ( notAllowed.length ) { + rule0.condition.excludedDomains = notAllowed; + } + addRules.push(rule0); + } + if ( isSameRules(addRules, beforeRules) ) { return false; } + return this.updateDynamicRules({ + addRules, + removeRuleIds: beforeRules.map(r => r.id), + }).then(( ) => + true + ).catch(( ) => + false + ); + }, + setExtensionActionOptions(...args) { + return nativeDNR.setExtensionActionOptions(...args); + }, +}; + +/******************************************************************************/ + +// Workaround for: +// https://github.com/uBlockOrigin/uBOL-home/issues/515 +// https://bugs.webkit.org/show_bug.cgi?id=300236 +// +// For each realm, we will force-reload registered rulesets once. + +const { windows } = webext; +const NORMAL_REALM = 0b01; +const PRIVATE_REALM = 0b10; +const ALL_REALMS = NORMAL_REALM | PRIVATE_REALM; +let seenRealms = 0b00; + +async function forceEnableRulesets(windowId) { + if ( seenRealms === ALL_REALMS ) { return; } + if ( windowId === windows.WINDOW_ID_NONE ) { return; } + const details = await windows.get(windowId, { windowTypes: [ 'normal' ] }); + const incognito = details?.incognito; + if ( typeof incognito !== 'boolean' ) { return; } + const currentRealm = incognito ? PRIVATE_REALM : NORMAL_REALM; + if ( (seenRealms & currentRealm) !== 0 ) { return; } + seenRealms |= currentRealm; + webext.storage.session.set({ __seenRealms: seenRealms }); + const ids = await nativeDNR.getEnabledRulesets(); + if ( ids.length === 0 ) { return; } + nativeDNR.updateEnabledRulesets({ + disableRulesetIds: ids.slice(), + enableRulesetIds: ids.slice(), + }); +} + +windows.onFocusChanged.addListener(forceEnableRulesets); + +webext.storage.session.get('__seenRealms').then(bin => { + seenRealms |= bin?.__seenRealms ?? 0; +}).catch(( ) => { +}); + diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/safari/manifest.json ublock-origin-1.67.0+dfsg/platform/mv3/safari/manifest.json --- ublock-origin-1.62.0+dfsg/platform/mv3/safari/manifest.json 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/safari/manifest.json 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,89 @@ +{ + "action": { + "default_icon": "/img/icon_64.png", + "default_popup": "popup.html" + }, + "author": "Raymond Hill", + "background": { + "scripts": [ "/js/background.js" ], + "type": "module", + "persistent": false + }, + "browser_specific_settings": { + "safari": { + "strict_min_version": "18.6" + } + }, + "commands": { + "enter-zapper-mode": { + "description": "__MSG_zapperTipEnter__" + }, + "enter-picker-mode": { + "description": "__MSG_pickerTipEnter__" + } + }, + "declarative_net_request": { + "rule_resources": [ + ] + }, + "default_locale": "en", + "description": "__MSG_extShortDesc__", + "icons": { + "16": "/img/icon_16.png", + "32": "/img/icon_32.png", + "64": "/img/icon_64.png", + "128": "/img/icon_128.png", + "512": "/img/icon_512.png" + }, + "manifest_version": 3, + "name": "__MSG_extName__", + "options_ui": { + "page": "dashboard.html" + }, + "host_permissions": [ + "" + ], + "permissions": [ + "activeTab", + "declarativeNetRequest", + "declarativeNetRequestWithHostAccess", + "scripting", + "storage" + ], + "short_name": "uBO Lite", + "version": "1.0", + "web_accessible_resources": [ + { + "resources": [ + "strictblock.html" + ], + "matches": [ + "" + ] + }, + { + "resources": [ + "zapper-ui.html" + ], + "matches": [ + "" + ] + }, + { + "resources": [ + "picker-ui.html" + ], + "matches": [ + "" + ] + }, + { + "resources": [ + "unpicker-ui.html" + ], + "matches": [ + "" + ] + } + ] +} diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/safari/patch-extension.js ublock-origin-1.67.0+dfsg/platform/mv3/safari/patch-extension.js --- ublock-origin-1.62.0+dfsg/platform/mv3/safari/patch-extension.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/safari/patch-extension.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,107 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import fs from 'fs/promises'; +import process from 'process'; + +/******************************************************************************/ + +const commandLineArgs = (( ) => { + const args = Object.create(null); + let name, value; + for ( const arg of process.argv.slice(2) ) { + const pos = arg.indexOf('='); + if ( pos === -1 ) { + name = arg; + value = ''; + } else { + name = arg.slice(0, pos); + value = arg.slice(pos+1); + } + args[name] = value; + } + return args; +})(); + +/******************************************************************************/ + +// Apple store rejects when description (extShortDesc) is longer than 112 +// characters. + +async function fixLongDescription(path) { + let text = await fs.readFile(path, { encoding: 'utf8' }); + const messages = JSON.parse(text); + let message = messages.extShortDesc.message; + if ( message.length <= 112 ) { return; } + const pos = message.indexOf('.'); + if ( pos !== -1 ) { + message = message.slice(0, pos+1); + } + if ( message.length >= 112 ) { + message = `${message.slice(0, 111)}…`; + } + messages.extShortDesc.message = message; + text = JSON.stringify(messages, null, 2); + await fs.writeFile(path, text); +} + +async function fixLongDescriptions() { + const promises = []; + const packageDir = commandLineArgs.packageDir; + const entries = await fs.readdir(`${packageDir}/_locales/`, { withFileTypes: true }); + for ( const entry of entries ) { + if ( entry.isDirectory() === false ) { continue; } + promises.push(fixLongDescription(`${packageDir}/_locales/${entry.name}/messages.json`)); + } + return Promise.all(promises); +} + +/******************************************************************************/ + +// Apple store rejects when version has four components. + +async function fixManifest() { + const packageDir = commandLineArgs.packageDir; + const path = `${packageDir}/manifest.json`; + let text = await fs.readFile(path, { encoding: 'utf8' }); + const manifest = JSON.parse(text); + const match = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/.exec(manifest.version); + if ( match === null ) { return; } + const month = parseInt(match[2], 10); + const dayofmonth = parseInt(match[3], 10); + const monthday /* sort of */ = month * 100 + dayofmonth; + manifest.version = `${match[1]}.${monthday}.${match[4]}`; + text = JSON.stringify(manifest, null, 2); + await fs.writeFile(path, text); +} + +/******************************************************************************/ + +async function main() { + await Promise.all([ + fixLongDescriptions(), + fixManifest(), + ]); +} + +main(); + +/******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/safari/patch-ruleset.js ublock-origin-1.67.0+dfsg/platform/mv3/safari/patch-ruleset.js --- ublock-origin-1.62.0+dfsg/platform/mv3/safari/patch-ruleset.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/safari/patch-ruleset.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,69 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +function patchRule(rule, out) { + const copy = structuredClone(rule); + const condition = copy.condition; + if ( copy.action.type === 'modifyHeaders' ) { return; } + if ( Array.isArray(copy.condition.responseHeaders) ) { return; } + // https://github.com/uBlockOrigin/uBOL-home/issues/476#issuecomment-3299309478 + if ( copy.action.redirect?.transform?.queryTransform?.removeParams ) { + const resourceTypes = condition.resourceTypes; + if ( resourceTypes?.includes('main_frame') ) { + condition.resourceTypes = resourceTypes.filter(a => a !== 'main_frame'); + if ( condition.resourceTypes.length === 0 ) { return; } + } + } + if ( Array.isArray(condition.initiatorDomains) ) { + condition.domains = condition.initiatorDomains; + delete condition.initiatorDomains; + } + if ( Array.isArray(condition.excludedInitiatorDomains) ) { + condition.excludedDomains = condition.excludedInitiatorDomains; + delete condition.excludedInitiatorDomains; + } + // https://github.com/uBlockOrigin/uBOL-home/issues/434 + let { urlFilter } = condition; + if ( urlFilter?.endsWith('^') ) { + urlFilter = urlFilter.slice(0, -1); + const match = /^(.*?\/\/|\|\|)/.exec(urlFilter); + const pattern = match + ? urlFilter.slice(match[0].length) + : urlFilter; + if ( /[^\w.%*-]/.test(pattern) ) { + const extra = structuredClone(copy); + extra.condition.urlFilter = `${urlFilter}|`; + out.push(extra); + console.log(`\tAdd ${extra.condition.urlFilter}`); + } + } + out.push(copy); + return copy; +} + +export function patchRuleset(ruleset) { + const out = []; + for ( const rule of ruleset ) { + if ( patchRule(rule, out) ) { continue; } + console.log(`\tReject ${JSON.stringify(rule)}`); + } + return out; +} diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/safe-replace.js ublock-origin-1.67.0+dfsg/platform/mv3/safe-replace.js --- ublock-origin-1.62.0+dfsg/platform/mv3/safe-replace.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/safe-replace.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,10 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - export function safeReplace(text, pattern, replacement, count = 1) { const rePattern = typeof pattern === 'string' ? new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/salvage-ruleids.mjs ublock-origin-1.67.0+dfsg/platform/mv3/salvage-ruleids.mjs --- ublock-origin-1.62.0+dfsg/platform/mv3/salvage-ruleids.mjs 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/salvage-ruleids.mjs 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ import fs from 'fs/promises'; @@ -64,15 +62,16 @@ ]; const writePromises = []; for ( const folder of folders ) { - const afterFiles = await fs.readdir(`${afterDir}/rulesets/${folder}`); + const afterFiles = await fs.readdir(`${afterDir}/rulesets/${folder}`).catch(( ) => { }); + if ( afterFiles === undefined ) { continue; } for ( const file of afterFiles ) { let raw = await fs.readFile(`${beforeDir}/rulesets/${folder}/${file}`, 'utf-8').catch(( ) => ''); let beforeRules; - try { beforeRules = JSON.parse(raw); } catch(_) { } + try { beforeRules = JSON.parse(raw); } catch { } if ( Array.isArray(beforeRules) === false ) { continue; } raw = await fs.readFile(`${afterDir}/rulesets/${folder}/${file}`, 'utf-8').catch(( ) => ''); let afterRules; - try { afterRules = JSON.parse(raw); } catch(_) { } + try { afterRules = JSON.parse(raw); } catch { } if ( Array.isArray(afterRules) === false ) { continue; } const beforeMap = new Map(beforeRules.map(a => { const id = a.id; diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/scriptlets/css-declarative.template.js ublock-origin-1.67.0+dfsg/platform/mv3/scriptlets/css-declarative.template.js --- ublock-origin-1.62.0+dfsg/platform/mv3/scriptlets/css-declarative.template.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/scriptlets/css-declarative.template.js 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/******************************************************************************* - - uBlock Origin Lite - a comprehensive, MV3-compliant content blocker - Copyright (C) 2014-present Raymond Hill - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see {http://www.gnu.org/licenses/}. - - Home: https://github.com/gorhill/uBlock -*/ - -/* jshint esversion:11 */ - -'use strict'; - -// ruleset: $rulesetId$ - -/******************************************************************************/ - -// Important! -// Isolate from global scope -(function uBOL_cssDeclarativeImport() { - -/******************************************************************************/ - -const argsList = self.$argsList$; - -const hostnamesMap = new Map(self.$hostnamesMap$); - -const entitiesMap = new Map(self.$entitiesMap$); - -const exceptionsMap = new Map(self.$exceptionsMap$); - -self.declarativeImports = self.declarativeImports || []; -self.declarativeImports.push({ argsList, hostnamesMap, entitiesMap, exceptionsMap }); - -/******************************************************************************/ - -})(); - -/******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/scriptlets/css-generic.template.js ublock-origin-1.67.0+dfsg/platform/mv3/scriptlets/css-generic.template.js --- ublock-origin-1.62.0+dfsg/platform/mv3/scriptlets/css-generic.template.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/scriptlets/css-generic.template.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,11 +19,7 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - -/******************************************************************************/ +// $rulesetId$ // Important! // Isolate from global scope @@ -31,28 +27,58 @@ /******************************************************************************/ -// $rulesetId$ - -const toImport = self.$genericSelectorMap$; - -const genericSelectorMap = self.genericSelectorMap || new Map(); - -if ( genericSelectorMap.size === 0 ) { - self.genericSelectorMap = new Map(toImport); - return; +const genericSelectorMap = self.$genericSelectorMap$; +const genericExceptionSieve = self.$genericExceptionSieve$; +const genericExceptionMap = self.$genericExceptionMap$; + +if ( genericSelectorMap ) { + const map = self.genericSelectorMap = + self.genericSelectorMap || new Map(); + if ( map.size !== 0 ) { + for ( const entry of genericSelectorMap ) { + const before = map.get(entry[0]); + if ( before === undefined ) { + map.set(entry[0], entry[1]); + } else { + map.set(entry[0], `${before},\n${entry[1]}`); + } + } + } else { + self.genericSelectorMap = new Map(genericSelectorMap); + } + genericSelectorMap.length = 0; } -for ( const toImportEntry of toImport ) { - const existing = genericSelectorMap.get(toImportEntry[0]); - genericSelectorMap.set( - toImportEntry[0], - existing === undefined - ? toImportEntry[1] - : `${existing},${toImportEntry[1]}` - ); +if ( genericExceptionSieve ) { + const hashes = self.genericExceptionSieve = + self.genericExceptionSieve || new Set(); + if ( hashes.size !== 0 ) { + for ( const hash of genericExceptionSieve ) { + hashes.add(hash); + } + } else { + self.genericExceptionSieve = new Set(genericExceptionSieve); + } + genericExceptionSieve.length = 0; } -self.genericSelectorMap = genericSelectorMap; +if ( genericExceptionMap ) { + const map = self.genericExceptionMap = + self.genericExceptionMap || new Map(); + if ( map.size !== 0 ) { + for ( const entry of genericExceptionMap ) { + const before = map.get(entry[0]); + if ( before === undefined ) { + map.set(entry[0], entry[1]); + } else { + map.set(entry[0], `${before}\n${entry[1]}`); + } + } + } else { + self.genericExceptionMap = new Map(genericExceptionMap); + } + genericExceptionMap.length = 0; +} /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/scriptlets/css-procedural.template.js ublock-origin-1.67.0+dfsg/platform/mv3/scriptlets/css-procedural.template.js --- ublock-origin-1.62.0+dfsg/platform/mv3/scriptlets/css-procedural.template.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/scriptlets/css-procedural.template.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,14 +19,8 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - // ruleset: $rulesetId$ -/******************************************************************************/ - // Important! // Isolate from global scope (function uBOL_cssProceduralImport() { @@ -34,15 +28,12 @@ /******************************************************************************/ const argsList = self.$argsList$; - +const argsSeqs = self.$argsSeqs$; const hostnamesMap = new Map(self.$hostnamesMap$); - -const entitiesMap = new Map(self.$entitiesMap$); - -const exceptionsMap = new Map(self.$exceptionsMap$); +const hasEntities = self.$hasEntities$; self.proceduralImports = self.proceduralImports || []; -self.proceduralImports.push({ argsList, hostnamesMap, entitiesMap, exceptionsMap }); +self.proceduralImports.push({ argsList, argsSeqs, hostnamesMap, hasEntities }); /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/scriptlets/css-specific.template.js ublock-origin-1.67.0+dfsg/platform/mv3/scriptlets/css-specific.template.js --- ublock-origin-1.62.0+dfsg/platform/mv3/scriptlets/css-specific.template.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/scriptlets/css-specific.template.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,14 +19,8 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - // ruleset: $rulesetId$ -/******************************************************************************/ - // Important! // Isolate from global scope (function uBOL_cssSpecificImports() { @@ -34,15 +28,12 @@ /******************************************************************************/ const argsList = self.$argsList$; - +const argsSeqs = self.$argsSeqs$; const hostnamesMap = new Map(self.$hostnamesMap$); - -const entitiesMap = new Map(self.$entitiesMap$); - -const exceptionsMap = new Map(self.$exceptionsMap$); +const hasEntities = self.$hasEntities$; self.specificImports = self.specificImports || []; -self.specificImports.push({ argsList, hostnamesMap, entitiesMap, exceptionsMap }); +self.specificImports.push({ argsList, argsSeqs, hostnamesMap, hasEntities }); /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/platform/mv3/scriptlets/scriptlet.template.js ublock-origin-1.67.0+dfsg/platform/mv3/scriptlets/scriptlet.template.js --- ublock-origin-1.62.0+dfsg/platform/mv3/scriptlets/scriptlet.template.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/mv3/scriptlets/scriptlet.template.js 2025-10-25 19:32:51.000000000 +0000 @@ -20,128 +20,97 @@ */ -/* eslint-disable indent */ - // ruleset: $rulesetId$ -/******************************************************************************/ - // Important! // Isolate from global scope // Start of local scope -(( ) => { +(function uBOL_$scriptletName$() { /******************************************************************************/ -// Start of code to inject -const uBOL_$scriptletName$ = function() { +function $scriptletName$(){} -const scriptletGlobals = {}; // eslint-disable-line +/******************************************************************************/ +const scriptletGlobals = {}; // eslint-disable-line const argsList = self.$argsList$; - const hostnamesMap = new Map(self.$hostnamesMap$); - -const entitiesMap = new Map(self.$entitiesMap$); - const exceptionsMap = new Map(self.$exceptionsMap$); +const hasEntities = self.$hasEntities$; +const hasAncestors = self.$hasAncestors$; -/******************************************************************************/ - -function $scriptletName$(){} - -/******************************************************************************/ - -const hnParts = []; -try { - let origin = document.location.origin; - if ( origin === 'null' ) { - const origins = document.location.ancestorOrigins; - for ( let i = 0; i < origins.length; i++ ) { - origin = origins[i]; - if ( origin !== 'null' ) { break; } +const collectArgIndices = (hn, map, out) => { + let argsIndices = map.get(hn); + if ( argsIndices === undefined ) { return; } + if ( typeof argsIndices !== 'number' ) { + for ( const argsIndex of argsIndices ) { + out.add(argsIndex); } + } else { + out.add(argsIndices); } - const pos = origin.lastIndexOf('://'); - if ( pos === -1 ) { return; } - hnParts.push(...origin.slice(pos+3).split('.')); -} -catch(ex) { } -const hnpartslen = hnParts.length; -if ( hnpartslen === 0 ) { return; } - -const todoIndices = new Set(); -const tonotdoIndices = []; +}; -// Exceptions -if ( exceptionsMap.size !== 0 ) { +const indicesFromHostname = (hostname, suffix = '') => { + const hnParts = hostname.split('.'); + const hnpartslen = hnParts.length; + if ( hnpartslen === 0 ) { return; } for ( let i = 0; i < hnpartslen; i++ ) { - const hn = hnParts.slice(i).join('.'); - const excepted = exceptionsMap.get(hn); - if ( excepted ) { tonotdoIndices.push(...excepted); } + const hn = `${hnParts.slice(i).join('.')}${suffix}`; + collectArgIndices(hn, hostnamesMap, todoIndices); + collectArgIndices(hn, exceptionsMap, tonotdoIndices); } - exceptionsMap.clear(); -} - -// Hostname-based -if ( hostnamesMap.size !== 0 ) { - const collectArgIndices = hn => { - let argsIndices = hostnamesMap.get(hn); - if ( argsIndices === undefined ) { return; } - if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; } - for ( const argsIndex of argsIndices ) { - if ( tonotdoIndices.includes(argsIndex) ) { continue; } - todoIndices.add(argsIndex); + if ( hasEntities ) { + const n = hnpartslen - 1; + for ( let i = 0; i < n; i++ ) { + for ( let j = n; j > i; j-- ) { + const en = `${hnParts.slice(i,j).join('.')}.*${suffix}`; + collectArgIndices(en, hostnamesMap, todoIndices); + collectArgIndices(en, exceptionsMap, tonotdoIndices); + } } - }; - for ( let i = 0; i < hnpartslen; i++ ) { - const hn = hnParts.slice(i).join('.'); - collectArgIndices(hn); } - collectArgIndices('*'); - hostnamesMap.clear(); -} +}; -// Entity-based -if ( entitiesMap.size !== 0 ) { - const n = hnpartslen - 1; - for ( let i = 0; i < n; i++ ) { - for ( let j = n; j > i; j-- ) { - const en = hnParts.slice(i,j).join('.'); - let argsIndices = entitiesMap.get(en); - if ( argsIndices === undefined ) { continue; } - if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; } - for ( const argsIndex of argsIndices ) { - if ( tonotdoIndices.includes(argsIndex) ) { continue; } - todoIndices.add(argsIndex); - } - } +const entries = (( ) => { + const docloc = document.location; + const origins = [ docloc.origin ]; + if ( docloc.ancestorOrigins ) { + origins.push(...docloc.ancestorOrigins); + } + return origins.map((origin, i) => { + const beg = origin.lastIndexOf('://'); + if ( beg === -1 ) { return; } + const hn = origin.slice(beg+3) + const end = hn.indexOf(':'); + return { hn: end === -1 ? hn : hn.slice(0, end), i }; + }).filter(a => a !== undefined); +})(); +if ( entries.length === 0 ) { return; } + +const todoIndices = new Set(); +const tonotdoIndices = new Set(); + +indicesFromHostname(entries[0].hn); +if ( hasAncestors ) { + for ( const entry of entries ) { + if ( entry.i === 0 ) { continue; } + indicesFromHostname(entry.hn, '>>'); } - entitiesMap.clear(); } // Apply scriplets for ( const i of todoIndices ) { + if ( tonotdoIndices.has(i) ) { continue; } try { $scriptletName$(...argsList[i]); } - catch(ex) {} + catch { } } -argsList.length = 0; - -/******************************************************************************/ - -}; -// End of code to inject - -/******************************************************************************/ - -uBOL_$scriptletName$(); /******************************************************************************/ // End of local scope })(); -/******************************************************************************/ - void 0; diff -Nru ublock-origin-1.62.0+dfsg/platform/nodejs/build.js ublock-origin-1.67.0+dfsg/platform/nodejs/build.js --- ublock-origin-1.62.0+dfsg/platform/nodejs/build.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/nodejs/build.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,12 +19,7 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - import fs from 'fs'; - import { pslInit } from './index.js'; /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/platform/nodejs/index.js ublock-origin-1.67.0+dfsg/platform/nodejs/index.js --- ublock-origin-1.62.0+dfsg/platform/nodejs/index.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/nodejs/index.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,6 +19,8 @@ Home: https://github.com/gorhill/uBlock */ +/* globals process */ + import * as s14e from './js/s14e-serializer.js'; import * as sfp from './js/static-filtering-parser.js'; @@ -188,7 +190,7 @@ useLists.promise = Promise.all(promises); await useLists.promise; - useLists.promise = null; // eslint-disable-line require-atomic-updates + useLists.promise = null; // Commit changes snfe.freeze(); @@ -283,7 +285,7 @@ // module.exports. Once all included files are written like ES modules, using // export statements, this should no longer be necessary. if ( typeof module !== 'undefined' && typeof exports !== 'undefined' ) { - module.exports = exports; + module.exports = exports; // eslint-disable-line no-undef } export { diff -Nru ublock-origin-1.62.0+dfsg/platform/npm/.eslintrc.json ublock-origin-1.67.0+dfsg/platform/npm/.eslintrc.json --- ublock-origin-1.62.0+dfsg/platform/npm/.eslintrc.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/npm/.eslintrc.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -{ - "root": true, - "env": { - "es2021": true, - "node": true - }, - "extends": "eslint:recommended", - "parserOptions": { - "ecmaVersion": 12, - "sourceType": "module" - }, - "rules": { - "eqeqeq": [ "warn", "always" ], - "indent": [ - "warn", - 4, - { - "ArrayExpression": "first", - "CallExpression": { "arguments": "first" }, - "MemberExpression": "off", - "ObjectExpression": "off", - "ignoreComments": true, - "ignoredNodes": [ - "AssignmentExpression:has(Literal)" - ] - } - ], - "getter-return": "off", - "no-control-regex": "off", - "no-empty": [ "error", { "allowEmptyCatch": true } ], - "no-promise-executor-return": [ "error" ], - "no-template-curly-in-string": [ "error" ], - "no-unreachable-loop": [ "error" ], - "no-useless-backreference": [ "error" ], - "no-useless-escape": "off", - "require-atomic-updates": [ "warn" ] - } -} diff -Nru ublock-origin-1.62.0+dfsg/platform/npm/demo.js ublock-origin-1.67.0+dfsg/platform/npm/demo.js --- ublock-origin-1.62.0+dfsg/platform/npm/demo.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/npm/demo.js 2025-10-25 19:32:51.000000000 +0000 @@ -31,8 +31,8 @@ * * */ -import fs from 'fs/promises'; import { StaticNetFilteringEngine } from '@gorhill/ubo-core'; +import fs from 'fs/promises'; /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/platform/npm/package-lock.json ublock-origin-1.67.0+dfsg/platform/npm/package-lock.json --- ublock-origin-1.62.0+dfsg/platform/npm/package-lock.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/npm/package-lock.json 2025-10-25 19:32:51.000000000 +0000 @@ -1,3051 +1,18 @@ { "name": "@gorhill/ubo-core", - "version": "0.1.26", - "lockfileVersion": 2, + "version": "0.1.30", + "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@gorhill/ubo-core", - "version": "0.1.26", + "version": "0.1.30", "license": "GPL-3.0-or-later", - "devDependencies": { - "c8": "^7.12.0", - "eslint": "^8.29.0", - "esm-world": "0.1.3", - "mocha": "^10.2.0", - "scaling-palm-tree": "github:mjethani/scaling-palm-tree#15cf1ab37e038771e1ff8005edc46d95f176739f" - }, + "devDependencies": {}, "engines": { - "node": ">=14.0.0", + "node": ">=18.0.0", "npm": ">=6.14.4" } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.15.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", - "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "node_modules/c8": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz", - "integrity": "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@istanbuljs/schema": "^0.1.3", - "find-up": "^5.0.0", - "foreground-child": "^2.0.0", - "istanbul-lib-coverage": "^3.2.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-reports": "^3.1.4", - "rimraf": "^3.0.2", - "test-exclude": "^6.0.0", - "v8-to-istanbul": "^9.0.0", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9" - }, - "bin": { - "c8": "bin/c8.js" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/c8/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - } - }, - "node_modules/chalk/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - } - }, - "node_modules/chalk/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/chalk/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true - }, - "node_modules/deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "node_modules/eslint": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", - "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.15.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/esm-world": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/esm-world/-/esm-world-0.1.3.tgz", - "integrity": "sha512-nzgmXAdSIuKf11R6Y1gFnnVkARCYvDobcPAdt85aKxw8lH5QOkwpdJ/2ezC/FIRSRxuebq/lsXnRVNRtJCyzDQ==", - "dev": true, - "engines": { - "node": ">=14.0.0", - "npm": ">=6.14.4" - } - }, - "node_modules/espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fastq": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", - "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "node_modules/flatted": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", - "dev": true - }, - "node_modules/foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - } - }, - "node_modules/globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/ignore": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", - "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/js-sdsl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", - "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "dev": true, - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "node_modules/scaling-palm-tree": { - "resolved": "git+ssh://git@github.com/mjethani/scaling-palm-tree.git#15cf1ab37e038771e1ff8005edc46d95f176739f", - "dev": true - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "node_modules/signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - } - }, - "dependencies": { - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.15.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@humanwhocodes/config-array": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", - "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "requires": { - "fill-range": "^7.1.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "c8": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz", - "integrity": "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@istanbuljs/schema": "^0.1.3", - "find-up": "^5.0.0", - "foreground-child": "^2.0.0", - "istanbul-lib-coverage": "^3.2.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-reports": "^3.1.4", - "rimraf": "^3.0.2", - "test-exclude": "^6.0.0", - "v8-to-istanbul": "^9.0.0", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9" - }, - "dependencies": { - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true - } - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", - "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", - "dev": true, - "requires": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.15.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "dependencies": { - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - } - } - }, - "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true - }, - "esm-world": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/esm-world/-/esm-world-0.1.3.tgz", - "integrity": "sha512-nzgmXAdSIuKf11R6Y1gFnnVkARCYvDobcPAdt85aKxw8lH5QOkwpdJ/2ezC/FIRSRxuebq/lsXnRVNRtJCyzDQ==", - "dev": true - }, - "espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", - "dev": true, - "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - } - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fastq": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", - "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", - "dev": true - }, - "foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "ignore": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", - "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true - }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "js-sdsl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", - "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "dev": true, - "requires": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "scaling-palm-tree": { - "version": "git+ssh://git@github.com/mjethani/scaling-palm-tree.git#15cf1ab37e038771e1ff8005edc46d95f176739f", - "dev": true, - "from": "scaling-palm-tree@github:mjethani/scaling-palm-tree#15cf1ab37e038771e1ff8005edc46d95f176739f" - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true - }, - "workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true - }, - "yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true } } } diff -Nru ublock-origin-1.62.0+dfsg/platform/npm/package.json ublock-origin-1.67.0+dfsg/platform/npm/package.json --- ublock-origin-1.62.0+dfsg/platform/npm/package.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/npm/package.json 2025-10-25 19:32:51.000000000 +0000 @@ -5,11 +5,7 @@ "type": "module", "main": "index.js", "scripts": { - "build": "node build.js", - "lint": "eslint js/ *.js tests/*.js", - "test": "c8 --include=index.js --include=js/**/*.js node test.js --mocha", - "test-full-battery": "c8 --include=index.js --include=js/**/*.js node test.js --mocha --full-battery", - "check-leaks": "mocha --check-leaks tests/leaks.js" + "build": "node build.js" }, "repository": { "type": "git", @@ -35,10 +31,5 @@ "npm": ">=6.14.4" }, "devDependencies": { - "c8": "^7.12.0", - "eslint": "^8.29.0", - "esm-world": "0.1.3", - "mocha": "^10.2.0", - "scaling-palm-tree": "github:mjethani/scaling-palm-tree#15cf1ab37e038771e1ff8005edc46d95f176739f" } } diff -Nru ublock-origin-1.62.0+dfsg/platform/npm/test.js ublock-origin-1.67.0+dfsg/platform/npm/test.js --- ublock-origin-1.62.0+dfsg/platform/npm/test.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/npm/test.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,15 +19,10 @@ Home: https://github.com/gorhill/uBlock */ -/* eslint-disable-next-line no-redeclare */ /* globals process */ -'use strict'; - -/******************************************************************************/ - -import { spawn } from "child_process"; import { promisify } from 'util'; +import { spawn } from "child_process"; /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/platform/opera/manifest.json ublock-origin-1.67.0+dfsg/platform/opera/manifest.json --- ublock-origin-1.62.0+dfsg/platform/opera/manifest.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/platform/opera/manifest.json 2025-10-25 19:32:51.000000000 +0000 @@ -88,7 +88,7 @@ }, "incognito": "split", "manifest_version": 2, - "minimum_opera_version": "67.0", + "minimum_opera_version": "79.0", "name": "uBlock Origin", "options_page": "dashboard.html", "permissions": [ diff -Nru ublock-origin-1.62.0+dfsg/src/1p-filters.html ublock-origin-1.67.0+dfsg/src/1p-filters.html --- ublock-origin-1.62.0+dfsg/src/1p-filters.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/1p-filters.html 2025-10-25 19:32:51.000000000 +0000 @@ -3,6 +3,7 @@ + uBlock — Your filters diff -Nru ublock-origin-1.62.0+dfsg/src/3p-filters.html ublock-origin-1.67.0+dfsg/src/3p-filters.html --- ublock-origin-1.62.0+dfsg/src/3p-filters.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/3p-filters.html 2025-10-25 19:32:51.000000000 +0000 @@ -3,6 +3,7 @@ + uBlock — Filter lists diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/ar/messages.json ublock-origin-1.67.0+dfsg/src/_locales/ar/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/ar/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/ar/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -100,11 +100,11 @@ "description": "English: or" }, "popupBlockedOnThisPage_v2": { - "message": "محجوب من هذه الصفحة", + "message": "محجوب على هذه الصفحة", "description": "For the new mobile-friendly popup design" }, "popupBlockedSinceInstall_v2": { - "message": "تم حظره منذ التثبيت", + "message": "حُجِب منذ التنصيب", "description": "For the new mobile-friendly popup design" }, "popupDomainsConnected_v2": { @@ -188,7 +188,7 @@ "description": "Tooltip for the no-scripting per-site switch" }, "popupNoPopups_v2": { - "message": "الإطارات المنبثقة", + "message": "نوافذ منبثقة", "description": "Caption for the no-popups per-site switch" }, "popupNoLargeMedia_v2": { @@ -196,7 +196,7 @@ "description": "Caption for the no-large-media per-site switch" }, "popupNoCosmeticFiltering_v2": { - "message": "إعادات الفلاتر التجميلية العمومية", + "message": "المرشحات التجميلية", "description": "Caption for the no-cosmetic-filtering per-site switch" }, "popupNoRemoteFonts_v2": { @@ -272,11 +272,11 @@ "description": "appears in popup" }, "popupVersion": { - "message": "نسخة", + "message": "الإصدار", "description": "Example of use: Version 1.26.4" }, "popup3pScriptFilter": { - "message": "سكربت", + "message": "برنامَج نصي", "description": "Appears as an option to filter out firewall rows" }, "popup3pFrameFilter": { @@ -340,7 +340,7 @@ "description": "Section for controlling user interface appearance" }, "settingsThemeLabel": { - "message": "المظاهر", + "message": "السمة", "description": "Label for checkbox to enable a custom dark theme" }, "settingsThemeAccent0Label": { @@ -444,7 +444,7 @@ "description": "English: Parse and enforce Adblock+ element hiding filters." }, "3pParseAllABPHideFiltersInfo": { - "message": "الفلاتر التجميلية تعمل لإزالة العناصر في صفحة الويب التي تعتبر إزعاج بصريًا و تلك التي لا يمكن حجبها عن طريق محركات التصفية القائمة على طلبات الشبكة.", + "message": "التشريحات التجميلية تعمل لإزالة العناصر في صفحة الويب التي تعتبر إزعاج بصريًا و تلك التي لا يمكن حجبها عن طريق محركات التشريحات القائمة على طلبات الشبكة.", "description": "Describes the purpose of the 'Parse and enforce cosmetic filters' feature." }, "3pIgnoreGenericCosmeticFilters": { @@ -452,11 +452,11 @@ "description": "This will cause uBO to ignore all generic cosmetic filters." }, "3pIgnoreGenericCosmeticFiltersInfo": { - "message": "الفلاتر التجميلية العمومية هي الفلاتر التجميلية التي تنطبق على كل مواقع الإنترنت. تفعيل هذا الخيار سوف يترك مساحة أقل من الذاكرة و قوة المعالجة للإستعمال من قبل صفحات الويب كنتيجة لمعالجة الفلاتر التجميلية العمومية.\n\nمن الأفضل تفعيل هذا الخيار على الأجهزة الأقل قوة.", + "message": "التشريحات التجميلية العمومية هي الفلاتر التجميلية التي تنطبق على كل مواقع الإنترنت. تفعيل هذا الخيار سوف يترك مساحة أقل من الذاكرة و قوة المعالجة للاستعمال من قبل صفحات الويب كنتيجة لمعالجة التشريحات التجميلية العمومية.\n\nمن الأفضل تفعيل هذا الخيار على الأجهزة الأقل قوة.", "description": "Describes the purpose of the 'Ignore generic cosmetic filters' feature." }, "3pSuspendUntilListsAreLoaded": { - "message": "تعليق نشاط الشبكة حتى يتم تحميل كافة قوائم عوامل التصفية", + "message": "تعليق نشاط الشبكة حتى يتم تحميل كافة قوائم عوامل التشريحات", "description": "A checkbox in the 'Filter lists' pane" }, "3pListsOfBlockedHostsHeader": { @@ -508,7 +508,7 @@ "description": "Filter lists section name" }, "3pImport": { - "message": "إسترجاع...", + "message": "إسترجاع…", "description": "The label for the checkbox used to import external filter lists" }, "3pExternalListsHint": { @@ -528,7 +528,7 @@ "description": "used as a tooltip for the clock icon beside a list" }, "3pUpdating": { - "message": "جار التحديث...", + "message": "جار التحديث…", "description": "used as a tooltip for the spinner icon beside a list" }, "3pNetworkError": { @@ -540,15 +540,15 @@ "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { - "message": "تفعيل تصفياتي المخصصة", + "message": "مكّن تشريحاتي المخصصة", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { - "message": "السماح بالفلاتر المخصصة التي تتطلب الثقة", + "message": "السماح بالتشريحات المخصصة التي تتطلب الثقة", "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { - "message": "استيراد و إضافة", + "message": "استورد وألحق…", "description": "Button in the 'My filters' pane" }, "1pExport": { @@ -592,7 +592,7 @@ "description": "Will discard manually-edited content and exit manual-edit mode" }, "rulesImport": { - "message": "الاستيراد من ملف...", + "message": "استورد من ملف…", "description": "" }, "rulesExport": { @@ -628,15 +628,15 @@ "description": "English: a sort option for list of rules." }, "whitelistPrompt": { - "message": "تحدد توجيهات الموقع الموثوق به صفحات الويب التي يجب تعطيل uBlock Origin عليها.\nأدخل رابط واحد كل سطر. ", + "message": "تحدد توجيهات المواقع الموثوقة الصفحات التي يجب تعطيل uBlock Origin عليها. إدخال واحد في كل سطر.", "description": "A concise description of the 'Trusted sites' pane." }, "whitelistImport": { - "message": "استيراد و إضافة", + "message": "استورد وألحق…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { - "message": "تصدير", + "message": "صدّر…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExportFilename": { @@ -676,11 +676,11 @@ "description": "Appears in the logger's tab selector" }, "loggerReloadTip": { - "message": "إعادة تحميل محتوى علامة التبويب", + "message": "أعد تحميل محتوى علامة التبويب", "description": "Tooltip for the reload button in the logger page" }, "loggerDomInspectorTip": { - "message": "تفعيل أو تعطيل مراقب DOM", + "message": "بدّل فاحص DOM", "description": "Tooltip for the DOM inspector button in the logger page" }, "loggerPopupPanelTip": { @@ -692,19 +692,19 @@ "description": "Tooltip for the top-right info label in the logger page" }, "loggerClearTip": { - "message": "امسح السجلات", + "message": "امسح المُسجّل", "description": "Tooltip for the eraser in the logger page; used to blank the content of the logger" }, "loggerPauseTip": { - "message": "ايقاف التسجيل مؤقتا (استبعاد كل البيانات الواردة) ", + "message": "أوقف المُسجّل مؤقتا (استبعاد كل البيانات الواردة)", "description": "Tooltip for the pause button in the logger page" }, "loggerUnpauseTip": { - "message": "استىئناف حافظ السجلات", + "message": "استئناف حافظ السجلات", "description": "Tooltip for the play button in the logger page" }, "loggerRowFiltererButtonTip": { - "message": "تبديل ترشيح بيانات التسجيل ", + "message": "بدّل ترشيح المُسجّل", "description": "Tooltip for the row filterer button in the logger page" }, "logFilterPrompt": { @@ -748,11 +748,11 @@ "description": "Small header to identify the 'Details' pane for a specific logger entry" }, "loggerEntryDetailsFilter": { - "message": "فلتر", + "message": "المرشّح", "description": "Label to identify a filter field" }, "loggerEntryDetailsFilterList": { - "message": "قائمة الفلتر", + "message": "قائمة المرشحات", "description": "Label to identify a filter list field" }, "loggerEntryDetailsRule": { @@ -832,15 +832,15 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringFinderSentence1": { - "message": "فلتر ثابت {{filter}} موجود في:", + "message": "تصفية ثابتة {{filter}} موجود في:", "description": "Below this sentence, the filter list(s) in which the filter was found" }, "loggerStaticFilteringFinderSentence2": { - "message": "الفلتر الثابت لا يوجد في أي من قوائم الفلاتر المفعلة", + "message": "الترشيح الثابت لا يوجد في أي من قوائم التشريحات المفعلة", "description": "Message to show when a filter cannot be found in any filter lists" }, "loggerSettingDiscardPrompt": { - "message": "مدخلات السجل التي لا تطابق أيا من المعايير ستحذف تلقائيا:", + "message": "مدخلات المُسجّل التي لا تطابق أيا من المعايير ستتجاهل تلقائيا:", "description": "Logger setting: A sentence to describe the purpose of the settings below" }, "loggerSettingPerEntryMaxAge": { @@ -852,7 +852,7 @@ "description": "A logger setting" }, "loggerSettingPerTabMaxEntries": { - "message": "أبق بحد أقصى على {{input}} مدخلات في كل تبويبة", + "message": "أبق بحد أقصى على {{input}} مدخلات في كل لسان", "description": "A logger setting" }, "loggerSettingPerEntryLineCount": { @@ -912,7 +912,7 @@ "description": "Header of 'Documentation' section in Support pane" }, "supportS1P1": { - "message": "اقرأ الوثائق على uBlock/wiki للتعرف على جميع ميزات يو بلوك أوريجين.", + "message": "اقرأ الوثائق الموجودة في uBlock/wiki للتعرف على جميع ميزات uBlock Origin.", "description": "First paragraph of 'Documentation' section in Support pane" }, "supportS2H": { @@ -920,23 +920,23 @@ "description": "Header of 'Questions and support' section in Support pane" }, "supportS2P1": { - "message": "يتم توفير إجابات للأسئلة وأنواع أخرى من دعم المساعدة على subreddit /r/uBlockOrigin", + "message": "يتم توفير إجابات للأسئلة وأنواع أخرى من دعم المساعدة على subreddit /r/uBlockOriginuBlockOrigin/uAssets أداة تعقب المشكلات. يتطلب حساب GitHub..", + "message": "أبلغ عن مشكلات التصفية مع مواقع ويب معينة إلى uBlockOrigin/uAssets issue tracker. يتطلب حساب GitHub.", "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { - "message": "هام: تجنب استخدام أدوات الحظر الأخرى ذات الغرض المشابه مع يو بلوك أوريجين، حيث قد يتسبب ذلك في حدوث مشكلات في التصفية على مواقع ويب معينة.", + "message": "هام: تجنب استخدام أدوات حظر أخرى ذات أغراض مماثلة مع uBlock Origin، لأن ذلك قد يتسبب في مشكلات في التصفية على مواقع ويب معينة.", "description": "Second paragraph of 'Filter issues' section in Support pane" }, "supportS3P3": { - "message": "نصائح: تأكد من تحديث قوائم التصفية. المُسجِّل هو الأداة الأساسية لتشخيص المشكلات المتعلقة بالفلتر", + "message": "نصائح: تأكد من تحديث قوائم التصفية. المُسجِّل هو الأداة الأساسية لتشخيص المشكلات المتعلقة بالفلتر.", "description": "Third paragraph of 'Filter issues' section in Support pane" }, "supportS4H": { @@ -944,7 +944,7 @@ "description": "Header of 'Bug report' section in Support pane" }, "supportS4P1": { - "message": "الإبلاغ عن المشكلات المتعلقة بيو بلوك أوريجين نفسه إلى uBlockOrigin/uBlock-issue أداة تعقب المشكلات. يتطلب حساب GitHub.", + "message": "الإبلاغ عن المشكلات المتعلقة بيو بلوك أوريجين نفسه إلى uBlockOrigin/uBlock-issue أداة تعقب المشكلات. يتطلب حساب GitHub", "description": "First paragraph of 'Bug report' section in Support pane" }, "supportS5H": { @@ -952,7 +952,7 @@ "description": "Header of 'Troubleshooting Information' section in Support pane" }, "supportS5P1": { - "message": "فيما يلي معلومات فنية قد تكون مفيدة عندما يحاول المتطوعون مساعدتك في حل مشكلة ما.فيما يلي معلومات فنية قد تكون مفيدة عندما يحاول المتطوعون مساعدتك في حل مشكلة ما.", + "message": "فيما يلي معلومات فنية قد تكون مفيدة عندما يحاول المتطوعون مساعدتك في حل مشكلة ما.فيما يلي معلومات فنية قد تكون مفيدة عندما يحاول المتطوعون مساعدتك في حل مشكلة ما. ", "description": "First paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS5P2": { @@ -968,7 +968,7 @@ "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { - "message": "يتم تحديث قوائم الفلتر بشكل يومي. تحقق أن مشكلتك لم يتم مواجهتها في أحدث قوائم الفلتر", + "message": "يتم تحديث قوائم الفلتر بشكل يومي. تحقق أن مشكلتك لم يتم مواجهتها في أحدث قوائم الفلتر.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S2": { @@ -980,7 +980,7 @@ "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "صفحة الويب...", + "message": "صفحة الويب…", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { @@ -1000,11 +1000,11 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { - "message": "لديه مشاكل متعلقة بالخصوصية", + "message": "توجد مشكلات متعلقة بالخصوصية", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "الأعطال عند تمكين يو بلوك أوريجين", + "message": "أعطال عند تمكين uBlock Origin", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { @@ -1016,7 +1016,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { - "message": "تسمية صفحة الويب باسم \"NSFW\" (\"ليس آمن للعمل\"\n", + "message": "ضع علامة على صفحة الويب بـ ”NSFW“ (”غير آمن للعمل“)", "description": "A checkbox to use for NSFW sites" }, "supportRedact": { @@ -1060,15 +1060,15 @@ "description": "Shown in the About pane" }, "aboutCDNs": { - "message": "يتم استضافة قوائم عوامل التصفية الخاصة بـ uBO بحرية على ما يلي CDNs:", + "message": "قوائم التصفية الخاصة بـ uBO مستضافة مجانًا على CDNs التالية:", "description": "Shown in the About pane" }, "aboutCDNsInfo": { - "message": "يتم استخدام CDN الذي تم اختياره عشوائيًا عند الحاجة إلى تحديث قائمة عوامل التصفية", + "message": "يتم استخدام CDN الذي تم اختياره عشوائيًا عند الحاجة إلى تحديث قائمة عوامل التصفية.", "description": "Shown in the About pane" }, "aboutBackupDataButton": { - "message": "النسخ الإحتياطي إلى ملف", + "message": "النسخ الإحتياطي إلى ملف…", "description": "Text for button to create a backup of all settings" }, "aboutBackupFilename": { @@ -1076,7 +1076,7 @@ "description": "English: my-ublock-backup_{{datetime}}.txt" }, "aboutRestoreDataButton": { - "message": "إسترجع من الملف...", + "message": "إسترجع من الملف…", "description": "English: Restore from file..." }, "aboutResetDataButton": { @@ -1172,7 +1172,7 @@ "description": "English: Close this window" }, "docblockedDontWarn": { - "message": "لا تحذرني لهذا الموقع مرة أخرى", + "message": "لا تحذرني مرة أخرى بشأن هذا الموقع", "description": "Label for checkbox in document-blocked page" }, "docblockedProceed": { @@ -1195,6 +1195,22 @@ "message": "الصفحة المحظورة تريد إعادة توجيهك إلى موقع آخر. إذا اخترت المتابعة، فسوف تنتقل مباشرة إلى: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "السبب:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "ضار", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "متتبع", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "سيئ السمعة", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "التصدير إلى سحابة التخزين", "description": "tooltip" @@ -1236,11 +1252,11 @@ "description": "" }, "contextMenuBlockElementInFrame": { - "message": "احظر العنصر في البرواز...", + "message": "احظر العنصر في الإطار…", "description": "An entry in the browser's contextual menu" }, "contextMenuSubscribeToList": { - "message": "اشترك في قائمة التصفية ...", + "message": "اشترك في قائمة التصفية…", "description": "An entry in the browser's contextual menu" }, "contextMenuTemporarilyAllowLargeMediaElements": { @@ -1248,7 +1264,7 @@ "description": "A context menu entry, present when large media elements have been blocked on the current site" }, "contextMenuViewSource": { - "message": "عرض المصدر…", + "message": "عرض كود المصدر…", "description": "A context menu entry, to view the source code of the target resource" }, "shortcutCapturePlaceholder": { @@ -1284,15 +1300,15 @@ "description": " In Setting pane, renders as (example): Storage used: 13.2 MB" }, "KB": { - "message": "كيلو بايت", + "message": "كيلوبايت", "description": "short for 'kilobytes'" }, "MB": { - "message": "ميغا بايت", + "message": "ميجابايت", "description": "short for 'megabytes'" }, "GB": { - "message": "جيغا بايت", + "message": "جيجابايت", "description": "short for 'gigabytes'" }, "clickToLoad": { diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/az/messages.json ublock-origin-1.67.0+dfsg/src/_locales/az/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/az/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/az/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Bulud yaddaşa göndər", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/be/messages.json ublock-origin-1.67.0+dfsg/src/_locales/be/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/be/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/be/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -228,7 +228,7 @@ "description": "Tooltip when hovering over the padlock in the dynamic filtering pane." }, "popupTipRevertRules": { - "message": "Націсніце, каб скасаваць змены.", + "message": "Націсніце, каб вярнуць змены.", "description": "Tooltip when hovering over the eraser in the dynamic filtering pane." }, "popupAnyRulePrompt": { @@ -252,7 +252,7 @@ "description": "" }, "popup1pScriptRulePrompt": { - "message": "уласныя скрыпты", + "message": "Асноўныя скрыпты", "description": "" }, "popup3pScriptRulePrompt": { @@ -260,7 +260,7 @@ "description": "" }, "popup3pFrameRulePrompt": { - "message": "староннія рамкі", + "message": "староннія фрэймы", "description": "" }, "popupHitDomainCountPrompt": { @@ -308,7 +308,7 @@ "description": "English: Cosmetic filters" }, "pickerCosmeticFiltersHint": { - "message": "Клік, Ctrl-клік", + "message": "Націсканне, Ctrl + націсканне", "description": "English: Click, Ctrl-click" }, "pickerContextMenuEntry": { @@ -424,7 +424,7 @@ "description": "Appears at the top of the _3rd-party filters_ pane" }, "3pListsOfBlockedHostsPerListStats": { - "message": "{{used}} выкарыстана з {{total}}", + "message": "Выкарыстана: {{used}} з {{total}}", "description": "Appears aside each filter list in the _3rd-party filters_ pane" }, "3pAutoUpdatePrompt1": { @@ -740,7 +740,7 @@ "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltin3p": { - "message": "старонні", + "message": "староннія", "description": "A keyword in the built-in row filtering expression" }, "loggerEntryDetailsHeader": { @@ -796,7 +796,7 @@ "description": "Small header to identify the static filtering section" }, "loggerStaticFilteringSentence": { - "message": "{{action}} сеткавыя запыты {{type}}, {{br}}URL-адрас якіх супадае з {{url}} {{br}}і паходзяць з {{origin}},{{br}}{{importance}} ёсць адпаведны фільтр-вынятак.", + "message": "{{action}} сеткавыя запыты {{type}}, {{br}}URL-адрас якіх супадае з {{url}} {{br}}і якія паходзяць з {{origin}},{{br}}{{importance}} з'яўляюцца адпаведным фільтрам выключэння.", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartBlock": { @@ -932,11 +932,11 @@ "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { - "message": "Важна: Пазбягайце выкарыстання іншых блакавальнікаў аналагічнага прызначэння разам з uBlock Origin, паколькі гэта можа прывесці да праблем з фільтрамі на пэўных сайтах.", + "message": "Важна: Пазбягайце выкарыстання іншых блакавальнікаў падобнага прызначэння разам з uBlock Origin, паколькі гэта можа прывесці да праблем з фільтрамі на пэўных сайтах.", "description": "Second paragraph of 'Filter issues' section in Support pane" }, "supportS3P3": { - "message": "Парада: Упэўніцеся, што вашы спісы фільтраў абноўленыя. Логер — галоўны інструмент для дыягностыкі праблем, звязаных з фільтрамі.", + "message": "Парада: Пераканайцеся, што вашы спісы фільтраў знаходзяцца ў актуальным стане. Рэгістратар — гэта галоўны інструмент для дыягностыкі праблем, якія звязаны з фільтрамі.", "description": "Third paragraph of 'Filter issues' section in Support pane" }, "supportS4H": { @@ -956,7 +956,7 @@ "description": "First paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS5P2": { - "message": "Важна: Патэнцыйна прыватная або адчувальная інфармацыя тыпова рэдагуецца. Адрэдагаваная інфармацыя можа зрабіць цяжэйшым вырашэнне праблемы.", + "message": "Важна: Патэнцыйна прыватная або канфідэнцыяльныя зветскі прадвызначана рэдагуюцца. Адрэдагаваныя звесткі могуць ускладніць вырашэнне праблемы.", "description": "Second paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS6H": { @@ -984,7 +984,7 @@ "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { - "message": "-- Выберыце запіс праблемы --", + "message": "-- Выберыце праблему --", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { @@ -1064,7 +1064,7 @@ "description": "Shown in the About pane" }, "aboutCDNsInfo": { - "message": "Калі спіс фільтраў патрабуе абнаўлення, выкарыстоўваецца выпадкова выбраная сетка CDN", + "message": "Пры абнаўленні спіса фільтраў выкарыстоўваецца CDN, які выбіраецца выпадковым чынам", "description": "Shown in the About pane" }, "aboutBackupDataButton": { @@ -1100,7 +1100,7 @@ "description": "English: Network error: {{msg}}" }, "subscriberConfirm": { - "message": "Дадаць наступны URL-адрас да вашага спісу фільтраў?\n\nНазва: \"{{title}}\"\nURL: {{url}}", + "message": "Дадаць наступны URL-адрас да вашага спіса фільтраў?\n\nНазва: \"{{title}}\"\nURL-адрас: {{url}}", "description": "No longer used" }, "subscribeButton": { @@ -1112,7 +1112,7 @@ "description": "English: a minute ago" }, "elapsedManyMinutesAgo": { - "message": "{{value}} хвілін(ы) таму", + "message": "Хвілін таму: {{value}}", "description": "English: {{value}} minutes ago" }, "elapsedOneHourAgo": { @@ -1120,7 +1120,7 @@ "description": "English: an hour ago" }, "elapsedManyHoursAgo": { - "message": "{{value}} гадзін(ы) таму", + "message": "Гадзін таму: {{value}}", "description": "English: {{value}} hours ago" }, "elapsedOneDayAgo": { @@ -1128,7 +1128,7 @@ "description": "English: a day ago" }, "elapsedManyDaysAgo": { - "message": "{{value}} дні таму", + "message": "Дзён таму: {{value}}", "description": "English: {{value}} days ago" }, "showDashboardButton": { @@ -1195,6 +1195,22 @@ "message": "Заблакаваная старонка мае намер перанакіраваць на іншы сайт. Калі вырашыце працягнуць, вы пяройдзеце непасрэдна да: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Падстава:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Шкодная актыўнасць", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Трэкер", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Сумнеўны змест", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Экспартаваць у воблачнае сховішча", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/bg/messages.json ublock-origin-1.67.0+dfsg/src/_locales/bg/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/bg/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/bg/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -1195,6 +1195,22 @@ "message": "Блокираната страница иска да Ви пренасочи към друг сайт. Ако изберете да продължите, ще отидете директно на: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Причина:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Злонамерена", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Проследяване", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Неблагонадеждна", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Изнасяне в облачно хранилище", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/bn/messages.json ublock-origin-1.67.0+dfsg/src/_locales/bn/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/bn/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/bn/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -64,7 +64,7 @@ "description": "Title for the asset viewer page" }, "advancedSettingsPageName": { - "message": "উন্নত সেটিংস", + "message": "অ্যাডভান্সড সেটিংস", "description": "Title for the advanced settings page" }, "popupPowerSwitchInfo": { @@ -1012,7 +1012,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { - "message": "Leads to badware, phishing", + "message": "ব্যাডওয়্যার, প্রতারণমূলক জায়গায় নেয়", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { @@ -1192,9 +1192,25 @@ "description": "Button text to navigate to the blocked page" }, "docblockedRedirectPrompt": { - "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", + "message": "ব্লককৃত পাতাটি আরেকটি ওয়েবসাইটে নেয়। এগিয়ে যেতে চাইলে, সরাসরি এই জায়গায় যাবে: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "কারণ:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "ক্ষতিকারক", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "ট্র্যাকার", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "অখ্যাতিপূর্ণ", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "ক্লাউড সঞ্চয়ে রপ্তানি করুন", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/br_FR/messages.json ublock-origin-1.67.0+dfsg/src/_locales/br_FR/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/br_FR/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/br_FR/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -356,7 +356,7 @@ "description": "Checkbox to let user access advanced, technical features" }, "settingsPrefetchingDisabledPrompt": { - "message": "Diweredekaat ar \"rak-lenn\", pe diougan an oberoù war ar rouedad (evit ma ne gennaskfe ket ar rekedoù rouedad stanket)", + "message": "Diweredekaat ar \"rak-lenn\", pe diougan an oberoù war ar rouedad (evit ma ne gennaskfe ket rekedoù ar rouedadoù stanket)", "description": "English: " }, "settingsHyperlinkAuditingDisabledPrompt": { @@ -476,7 +476,7 @@ "description": "Filter lists section name" }, "3pGroupPrivacy": { - "message": "Prevezded", + "message": "Buhez prevez", "description": "Filter lists section name" }, "3pGroupMalware": { @@ -488,7 +488,7 @@ "description": "Filter lists section name" }, "3pGroupCookies": { - "message": "Kemennadennoù diwar-benn an toupinoù", + "message": "Notennoù diwar-benn an toupinoù", "description": "Filter lists section name" }, "3pGroupAnnoyances": { @@ -928,7 +928,7 @@ "description": "Header of 'Filter issues' section in Support pane" }, "supportS3P1": { - "message": "Danevellit kudennoù silañ e lec'hiennoù resis zo e-barzh roll evezhiañ kudennoù uBlockOrigin/uAssets. Ur c'hont GitHub zo rekis.", + "message": "Danevellit kudennoù ar siloù e lec'hiennoù resis e-barzh uBlockOrigin/uAssets roll evezhiañ kudennoù. Ur c'hont GitHub zo rekis.", "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Evit nompas sammañ ar genlabourerien a-youl vat gant meur a zanevell heñvel, gwiriit ma n'eo ket bet danevellet ho kudenn en ar-raok mar plij.", + "message": "Evit nompas sammañ ar genlabourerien a-youl vat gant meur a zanevell heñvel, gwiriit ma n'eo ket bet danevellet ho kudenn en a-raok mar plij.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1000,7 +1000,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { - "message": "Kudennoù a-fed prevezded he deus", + "message": "Kudennoù a-fed ar vuhez prevez he deus", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { @@ -1012,7 +1012,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { - "message": "Leads to badware, phishing", + "message": "Kas a ra da veziantoù droukyoulet pe d'an higennañ niverel", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { @@ -1028,7 +1028,7 @@ "description": "Text for 'Unredact' button" }, "aboutPrivacyPolicy": { - "message": "Politikerezh prevezded", + "message": "Politikerezh ar vuhez prevez", "description": "Link to privacy policy on GitHub (English)" }, "aboutChangelog": { @@ -1195,6 +1195,22 @@ "message": "Ar bajenn stanket a fell dezhi adkas d'ul lec'hienn all. M'ho peus c'hoant da genderc'hel e vioc'h kaset d'ar chomlec'h-mañ: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Abeg:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malisius", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Heulier", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Douetus", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Ezporzhiañ etrezek stokañ ar goumoulenn (cloud)", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/bs/messages.json ublock-origin-1.67.0+dfsg/src/_locales/bs/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/bs/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/bs/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -548,11 +548,11 @@ "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { - "message": "Uvezi i dodaj", + "message": "Uvezi i dodaj…", "description": "Button in the 'My filters' pane" }, "1pExport": { - "message": "Izvezi", + "message": "Izvoz…", "description": "Button in the 'My filters' pane" }, "1pExportFilename": { @@ -596,7 +596,7 @@ "description": "" }, "rulesExport": { - "message": "Izvezi u datoteku", + "message": "Izvoz u datoteku…", "description": "Button in the 'My rules' pane" }, "rulesDefaultFileName": { @@ -632,11 +632,11 @@ "description": "A concise description of the 'Trusted sites' pane." }, "whitelistImport": { - "message": "Uvezi i dodaj", + "message": "Uvezi i dodaj…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { - "message": "Izvezi", + "message": "Izvoz…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExportFilename": { @@ -928,7 +928,7 @@ "description": "Header of 'Filter issues' section in Support pane" }, "supportS3P1": { - "message": "Prijavite probleme s filtriranjem određenih web stranica na uBlockOrigin/uAssets stranici za praćenje problema. Potreban će vam biti GitHub račun.\n\n", + "message": "Prijavite probleme s filterima na određenim web stranicama uBlockOrigin/uAssets sistemu za praćenje problema . Potreban je GitHub račun.", "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { @@ -1012,7 +1012,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { - "message": "Leads to badware, phishing", + "message": "Vodi do zlonamjernog softvera i phishinga", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { @@ -1064,11 +1064,11 @@ "description": "Shown in the About pane" }, "aboutCDNsInfo": { - "message": "Slučajno odabrani CDN će biti korišten kada zapis filtera treba biti ažuriran", + "message": "Nasumično odabrana CDN mreža se koristi kada je potrebno ažurirati listu filtera.", "description": "Shown in the About pane" }, "aboutBackupDataButton": { - "message": "Sačuvaj rezervnu kopiju u datoteku", + "message": "Sačuvaj rezervnu kopiju u datoteku…", "description": "Text for button to create a backup of all settings" }, "aboutBackupFilename": { @@ -1192,9 +1192,25 @@ "description": "Button text to navigate to the blocked page" }, "docblockedRedirectPrompt": { - "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", + "message": "Blokirana stranica želi preusmjeriti na drugu stranicu. Ako odlučite nastaviti, bit ćete direktno na: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Razlog:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Zlonamjerno", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Praćenje", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Neugledno", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Izvezi u cloud pohranu", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/ca/messages.json ublock-origin-1.67.0+dfsg/src/_locales/ca/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/ca/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/ca/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -32,11 +32,11 @@ "description": "appears as tab name in dashboard" }, "1pPageName": { - "message": "Els vostres filtres", + "message": "Filtres personalitzats", "description": "appears as tab name in dashboard" }, "rulesPageName": { - "message": "Les meves regles", + "message": "Regles personalitzades", "description": "appears as tab name in dashboard" }, "whitelistPageName": { @@ -540,7 +540,7 @@ "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { - "message": "Habilita els meus filtres personalitzats", + "message": "Habilita els filtres personalitzats", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Crea un informe nou", + "message": "Crea un informe nou al GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Cerca d'informes semblants", + "message": "Cerca informes similars al GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Per evitar carregar els voluntaris amb informes duplicats, verifiqueu que el problema encara no s'hagi notificat.", + "message": "Per a evitar la sobrecàrrega del nostre voluntariat amb informes duplicats, verifiqueu abans que el problema encara no s'ha notificat. Nota: en fer clic, enviareu la pàgina causant al nostre GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "La pàgina blocada vol redirigir-vos a un altre web diferent. Si continueu, si us reenviarà a: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Motiu:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Perjudicial", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Seguidor", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Mala reputació", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exporta a un servei al núvol", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/cs/messages.json ublock-origin-1.67.0+dfsg/src/_locales/cs/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/cs/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/cs/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -1172,7 +1172,7 @@ "description": "English: Close this window" }, "docblockedDontWarn": { - "message": "Znova mě nevarujte ohladně této stránky", + "message": "Nevarujte mě znovu o této stránce", "description": "Label for checkbox in document-blocked page" }, "docblockedProceed": { @@ -1195,6 +1195,22 @@ "message": "Zablokovaná stránka vás chce přesměrovat na jiný web. Pokud se rozhodnete pokračovat, přejdete přímo na: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Důvod:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Zlomyslný", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Sledovač", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Nereputabilní", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exportovat do cloudového úložiště", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/cv/messages.json ublock-origin-1.67.0+dfsg/src/_locales/cv/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/cv/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/cv/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/cy/messages.json ublock-origin-1.67.0+dfsg/src/_locales/cy/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/cy/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/cy/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -540,7 +540,7 @@ "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { - "message": "Enable my custom filters", + "message": "Galluogi fy hidlyddion addasedig", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { @@ -548,7 +548,7 @@ "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { - "message": "Import and append…", + "message": "Mewnforio ac atodi...", "description": "Button in the 'My filters' pane" }, "1pExport": { @@ -560,19 +560,19 @@ "description": "English: my-ublock-static-filters_{{datetime}}.txt" }, "1pApplyChanges": { - "message": "Apply changes", + "message": "Rhoi'r newidiadau ar waith", "description": "English: Apply changes" }, "rulesPermanentHeader": { - "message": "Permanent rules", + "message": "Rheolau parhaol", "description": "header" }, "rulesTemporaryHeader": { - "message": "Temporary rules", + "message": "Rheolau dros dro", "description": "header" }, "rulesRevert": { - "message": "Revert", + "message": "Gwrthdroi", "description": "This will remove all temporary rules" }, "rulesCommit": { @@ -592,7 +592,7 @@ "description": "Will discard manually-edited content and exit manual-edit mode" }, "rulesImport": { - "message": "Import from file…", + "message": "Mewnforio o ffeil...", "description": "" }, "rulesExport": { @@ -632,7 +632,7 @@ "description": "A concise description of the 'Trusted sites' pane." }, "whitelistImport": { - "message": "Import and append…", + "message": "Mewnforio ac atodi...", "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { @@ -644,7 +644,7 @@ "description": "The default filename to use for import/export purpose" }, "whitelistApply": { - "message": "Apply changes", + "message": "Rhoi'r newidiadau ar waith", "description": "English: Apply changes" }, "logRequestsHeaderType": { @@ -780,7 +780,7 @@ "description": "Label to identify the URL of an entry" }, "loggerURLFilteringHeader": { - "message": "URL rule", + "message": "Rheol URL", "description": "Small header to identify the dynamic URL filtering section" }, "loggerURLFilteringContextLabel": { @@ -820,15 +820,15 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartAnyOrigin": { - "message": "from anywhere", + "message": "o unrhyw le", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartNotImportant": { - "message": "except when", + "message": "ac eithrio pan", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartImportant": { - "message": "even if", + "message": "hyd yn oed os", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringFinderSentence1": { @@ -948,7 +948,7 @@ "description": "First paragraph of 'Bug report' section in Support pane" }, "supportS5H": { - "message": "Troubleshooting Information", + "message": "Gwybodaeth datrys problemau", "description": "Header of 'Troubleshooting Information' section in Support pane" }, "supportS5P1": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1016,7 +1016,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { - "message": "Label the web page as “NSFW” (“Not Safe For Work”)", + "message": "Rhoi label “NSFW” (“Not Safe For Work”) ar y dudalen we", "description": "A checkbox to use for NSFW sites" }, "supportRedact": { @@ -1056,7 +1056,7 @@ "description": "Link text to uBO's own filter lists repo" }, "aboutDependencies": { - "message": "External dependencies (GPLv3-compatible):", + "message": "Gofynion allanol (cydnaws â GPLv3):", "description": "Shown in the About pane" }, "aboutCDNs": { @@ -1068,7 +1068,7 @@ "description": "Shown in the About pane" }, "aboutBackupDataButton": { - "message": "Back up to file…", + "message": "Copïo wrth gefn i ffeil...", "description": "Text for button to create a backup of all settings" }, "aboutBackupFilename": { @@ -1076,11 +1076,11 @@ "description": "English: my-ublock-backup_{{datetime}}.txt" }, "aboutRestoreDataButton": { - "message": "Restore from file…", + "message": "Adfer o ffeil...", "description": "English: Restore from file..." }, "aboutResetDataButton": { - "message": "Reset to default settings…", + "message": "Ailosod y gosodiadau i'r rhagosodiad...", "description": "English: Reset to default settings..." }, "aboutRestoreDataConfirm": { @@ -1096,7 +1096,7 @@ "description": "Message asking user to confirm reset" }, "errorCantConnectTo": { - "message": "Network error: {{msg}}", + "message": "Gwall rhwydwaith: {{msg}}", "description": "English: Network error: {{msg}}" }, "subscriberConfirm": { @@ -1148,7 +1148,7 @@ "description": "Used as a title for the document-blocked page" }, "docblockedPrompt1": { - "message": "uBlock Origin has prevented the following page from loading:", + "message": "Mae uBlock Origin wedi atal y dudalen ganlynol rhag llwytho:", "description": "Used in the strict-blocking page" }, "docblockedPrompt2": { @@ -1156,7 +1156,7 @@ "description": "Used in the strict-blocking page" }, "docblockedNoParamsPrompt": { - "message": "without parameters", + "message": "heb baramedrau", "description": "label to be used for the parameter-less URL: https://cloud.githubusercontent.com/assets/585534/9832014/bfb1b8f0-593b-11e5-8a27-fba472a5529a.png" }, "docblockedFoundIn": { @@ -1172,7 +1172,7 @@ "description": "English: Close this window" }, "docblockedDontWarn": { - "message": "Don't warn me again about this site", + "message": "Peidio â'm rhybuddio eto am y wefan hon", "description": "Label for checkbox in document-blocked page" }, "docblockedProceed": { @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" @@ -1296,7 +1312,7 @@ "description": "short for 'gigabytes'" }, "clickToLoad": { - "message": "Click to load", + "message": "Clicio i lwytho", "description": "Message used in frame placeholders" }, "linterMainReport": { diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/da/messages.json ublock-origin-1.67.0+dfsg/src/_locales/da/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/da/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/da/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Opret ny anmeldelse", + "message": "Opret ny anmeldelse på GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find lign. anmeldelser", + "message": "Find lign. anmeldelser på GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "For at undgå at belaste frivillige med dubletanmeldelser, så tjek venligst, at problemet ikke allerede er anmeldt.", + "message": "For at undgå at bebyrde frivillige med dubletanmeldelser, så tjek venligst, at problematikken ikke allerede er anmeldt. Bemærk: Ved at klikke på knappen, sendes sidens oprindelse til GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "Den blokerede side ønsker at omdirigere til et andet websted. Vælger man at fortsætte, navigeres direkte til: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Årsag:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Ondsindet", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Ikke-velrenommeret", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Eksportér til Skylager", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/de/messages.json ublock-origin-1.67.0+dfsg/src/_locales/de/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/de/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/de/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -308,7 +308,7 @@ "description": "English: Cosmetic filters" }, "pickerCosmeticFiltersHint": { - "message": "Klick, Strg-Klick", + "message": "Klick, Strg+Klick", "description": "English: Click, Ctrl-click" }, "pickerContextMenuEntry": { @@ -548,7 +548,7 @@ "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { - "message": "Importieren und anfügen …", + "message": "Importieren und ergänzen …", "description": "Button in the 'My filters' pane" }, "1pExport": { @@ -632,7 +632,7 @@ "description": "A concise description of the 'Trusted sites' pane." }, "whitelistImport": { - "message": "Importieren und anfügen …", + "message": "Importieren und ergänzen …", "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { @@ -888,7 +888,7 @@ "description": "Label for radio-button to pick export format" }, "loggerExportEncodePlain": { - "message": "Einfach", + "message": "Reiner Text", "description": "Label for radio-button to pick export text format" }, "loggerExportEncodeMarkdown": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Neue Meldung erstellen", + "message": "Neue Meldung auf GitHub erstellen", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Ähnliche Meldungen finden", + "message": "Ähnliche Meldungen auf GitHub finden", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Um die Freiwilligen nicht mit doppelten Meldungen zu belasten, vergewissern Sie sich bitte, dass das Problem nicht schon einmal gemeldet wurde.", + "message": "Um die Freiwilligen nicht mit doppelten Meldungen zu überlasten, vergewissern Sie sich bitte, dass das Problem noch nicht gemeldet wurde. Hinweis: Das Anklicken der Schaltfläche übermittelt den Ursprung der Seite an GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "Die blockierte Seite möchte zu einer anderen Website weiterleiten. Beim Fortfahren wird folgende Seite aufgerufen: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Grund:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Schädlich", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Unseriös", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "In den Cloud-Speicher exportieren", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/el/messages.json ublock-origin-1.67.0+dfsg/src/_locales/el/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/el/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/el/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -8,7 +8,7 @@ "description": "this will be in the Chrome web store: must be 132 characters or less" }, "dashboardName": { - "message": "uBlock₀ - Πίνακας ελέγχου", + "message": "uBlock₀ — Πίνακας ελέγχου", "description": "English: uBlock₀ — Dashboard" }, "dashboardUnsavedWarning": { @@ -40,7 +40,7 @@ "description": "appears as tab name in dashboard" }, "whitelistPageName": { - "message": "Αξιόπιστοι ιστότοποι", + "message": "Αξιόπιστες τοποθεσίες", "description": "appears as tab name in dashboard" }, "shortcutsPageName": { @@ -116,7 +116,7 @@ "description": "English: Click to open the dashboard" }, "popupTipZapper": { - "message": "Είσοδος σε λειτουργία εκτέλεσης στοιχείων", + "message": "Είσοδος σε λειτουργία αφαίρεσης στοιχείων", "description": "Tooltip for the element-zapper icon in the popup panel" }, "popupTipPicker": { @@ -468,7 +468,7 @@ "description": "English: Apply changes" }, "3pGroupDefault": { - "message": "Τοπικά", + "message": "Ενσωματωμένο", "description": "Filter lists section name" }, "3pGroupAds": { @@ -632,11 +632,11 @@ "description": "A concise description of the 'Trusted sites' pane." }, "whitelistImport": { - "message": "Εισαγωγή και προσάρτηση", + "message": "Εισαγωγή και προσθήκη…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { - "message": "Εξαγωγή", + "message": "Εξαγωγή…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExportFilename": { @@ -780,7 +780,7 @@ "description": "Label to identify the URL of an entry" }, "loggerURLFilteringHeader": { - "message": "Κανόνας URL", + "message": "Κανόνας διεύθυνσης URL", "description": "Small header to identify the dynamic URL filtering section" }, "loggerURLFilteringContextLabel": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Δημιουργία νέας αναφοράς", + "message": "Δημιουργία νέας αναφοράς στο Github", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Βρείτε παρόμοιες αναφορές", + "message": "Εύρεση παρόμοιων αναφορών στο GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -940,7 +940,7 @@ "description": "Third paragraph of 'Filter issues' section in Support pane" }, "supportS4H": { - "message": "Αναφορά σφαλμάτων", + "message": "Αναφορά σφάλματος", "description": "Header of 'Bug report' section in Support pane" }, "supportS4P1": { @@ -948,7 +948,7 @@ "description": "First paragraph of 'Bug report' section in Support pane" }, "supportS5H": { - "message": "Πληροφορίες αντιμετώπισης προβλημάτων", + "message": "Πληροφορίες για αντιμετώπιση προβλημάτων", "description": "Header of 'Troubleshooting Information' section in Support pane" }, "supportS5P1": { @@ -980,7 +980,7 @@ "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "Η ιστοσελίδα...", + "message": "Η ιστοσελίδα…", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { @@ -1032,7 +1032,7 @@ "description": "Link to privacy policy on GitHub (English)" }, "aboutChangelog": { - "message": "Αρχείο καταγραφής αλλαγών", + "message": "Αρχείο αλλαγών", "description": "" }, "aboutCode": { @@ -1092,7 +1092,7 @@ "description": "Message to display when an error occurred during restore" }, "aboutResetDataConfirm": { - "message": "Όλες οι ρυθμίσεις σας θα καταργηθούν και θα γίνει επανεκκίνηση του uBlock.\n\nΕπαναφορά του uBlock στις εργοστασιακές ρυθμίσεις;", + "message": "Όλες οι ρυθμίσεις σας θα καταργηθούν και θα γίνει επανεκκίνηση του uBlock₀.\n\nΕπαναφορά του uBlock₀ στις αρχικές ρυθμίσεις;", "description": "Message asking user to confirm reset" }, "errorCantConnectTo": { @@ -1195,6 +1195,22 @@ "message": "Η αποκλεισμένη σελίδα θέλει να κάνει ανακατεύθυνση σε άλλο ιστότοπο. Αν επιλέξετε να συνεχίσετε, θα μεταβείτε απευθείας στο: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Αιτία:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Κακόβουλος ιστότοπος", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Ιχνηλάτης", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Κακόφημος ιστότοπος", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Εξαγωγή στο cloud storage", "description": "tooltip" @@ -1236,7 +1252,7 @@ "description": "" }, "contextMenuBlockElementInFrame": { - "message": "Στοιχείο μπλοκ στο πλαίσιο...", + "message": "Αποκλεισμός στοιχείου σε frame…", "description": "An entry in the browser's contextual menu" }, "contextMenuSubscribeToList": { diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/en/messages.json ublock-origin-1.67.0+dfsg/src/_locales/en/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/en/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/en/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -901,11 +901,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -965,7 +965,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1197,6 +1197,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/en_GB/messages.json ublock-origin-1.67.0+dfsg/src/_locales/en_GB/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/en_GB/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/en_GB/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/eo/messages.json ublock-origin-1.67.0+dfsg/src/_locales/eo/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/eo/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/eo/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Eksporti al nuba konservado", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/es/messages.json ublock-origin-1.67.0+dfsg/src/_locales/es/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/es/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/es/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -536,7 +536,7 @@ "description": "used as a tooltip for error icon beside a list" }, "1pTrustWarning": { - "message": "No añadir filtros de fuentes no confiables.", + "message": "No añadas filtros de fuentes no confiables.", "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Crear nuevo reporte", + "message": "Crear nuevo reporte en GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Encontrar reportes similares", + "message": "Encontrar reportes similares en GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Para evitar sobrecargar a voluntarios con reportes duplicados, verifica que el problema no haya sido reportado.", + "message": "Para evitar sobrecargar a voluntarios con reportes duplicados, verifica que el problema no haya sido reportado. Nota: al hacer clic en el botón, hará que el origen de la página se envíe a GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "La página bloqueada quiere redirigir a otro sitio. Si eliges continuar, navegarás directamente a: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Razón:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicioso", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Rastreador", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Mala reputación", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exportar datos a la nube", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/et/messages.json ublock-origin-1.67.0+dfsg/src/_locales/et/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/et/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/et/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Loo uus aruanne", + "message": "Loo GitHubis uus aruanne", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Leia sarnaseid aruandeid", + "message": "Leia GitHubist sarnaseid aruandeid", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Vabatahtlike koormuse vähendamiseks veendu, et probleemi pole juba teatatud.", + "message": "Vabatahtlike koormuse vähendamiseks palun veendu, et probleemi ei ole juba teatatud. Märkus: nupu klõpsamine saadab lehe aadressi GitHubi.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "Tõkestatud veebileht üritab suunata muule veebilehele. Jätkates suunatakse teid veebilehele {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Põhjus:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Kahtlane", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Jälgija", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Kaak", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Ekspordi pilvehoidlasse", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/eu/messages.json ublock-origin-1.67.0+dfsg/src/_locales/eu/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/eu/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/eu/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -1192,9 +1192,25 @@ "description": "Button text to navigate to the blocked page" }, "docblockedRedirectPrompt": { - "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", + "message": "Blokeatutako orrialdeak beste helbide batera berbideratu nahi zaitu. Jarraitu nahi baduzu, zuzenean helbide honetara joango zara: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Esportatu hodei biltegiratzera", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/fa/messages.json ublock-origin-1.67.0+dfsg/src/_locales/fa/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/fa/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/fa/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "دلیل", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "ردیاب", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "صدور به فضای ذخیره سازی ابری", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/fi/messages.json ublock-origin-1.67.0+dfsg/src/_locales/fi/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/fi/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/fi/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Luo uusi ilmoitus", + "message": "Luo GitHubiin uusi ilmoitus", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Etsi samankaltaisia ilmoituksia", + "message": "Etsi GitHubista vastaavia ilmoituksia", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -948,11 +948,11 @@ "description": "First paragraph of 'Bug report' section in Support pane" }, "supportS5H": { - "message": "Vianmääritystiedot", + "message": "Vianselvitystiedot", "description": "Header of 'Troubleshooting Information' section in Support pane" }, "supportS5P1": { - "message": "Alla on teknisiä tietoja, joista voi olla hyötyä vapaaehtoisille, jotka pyrkivät auttamaan ongelmasi ratkaisussa.", + "message": "Alla on teknisiä tietoja, jotka saattavat auttaa ongelmasi ratkonnassa auttavia vapaaehtoisia.", "description": "First paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS5P2": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Välttääksesi vapaaehtoisten kuormittamisen ylimääräisillä ilmoituksilla, tarkista ensin onko ongelmasta jo ilmoitettu.", + "message": "Välttääksesi vapaaehtoisten kuormittamisen ylimääräisillä ilmoituksilla, tarkasta ensin onko ongelmasta jo ilmoitettu. Huomioi: Painikkeen painallus lähettää sivun osoitteen GitHubiin.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "Estetty sivu ohjautuu eri sivustolle. Jos jatkat, siirryt suoraan osoitteeseen {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Syy:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Haitallinen", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Seuranta", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Huonomaineinen", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Vie pilvitallennustilaan", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/fil/messages.json ublock-origin-1.67.0+dfsg/src/_locales/fil/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/fil/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/fil/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -484,11 +484,11 @@ "description": "Filter lists section name" }, "3pGroupSocial": { - "message": "Social widgets", + "message": "Panlipunang mga widget", "description": "Filter lists section name" }, "3pGroupCookies": { - "message": "Cookie notices", + "message": "Pabatid para sa mga cookie", "description": "Filter lists section name" }, "3pGroupAnnoyances": { @@ -540,11 +540,11 @@ "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { - "message": "Enable my custom filters", + "message": "Paganahin ang mga pasadyang filter", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { - "message": "Allow custom filters requiring trust", + "message": "Hayaan ang mga pansariling filter na kailangan ng tiwala", "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { @@ -1012,7 +1012,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { - "message": "Leads to badware, phishing", + "message": "Patungo sa badware o phishing", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { @@ -1192,9 +1192,25 @@ "description": "Button text to navigate to the blocked page" }, "docblockedRedirectPrompt": { - "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", + "message": "Nais nitong website na dalhin ka sa iss pang site. Kung tutuloy ka, pupunta ka sa: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "I-export sa imbakan sa cloud", "description": "tooltip" @@ -1272,7 +1288,7 @@ "description": "Label for keyboard shortcut used to toggle cosmetic filtering" }, "toggleJavascript": { - "message": "Toggle JavaScript", + "message": "Paganahin ang JavaScript ", "description": "Label for keyboard shortcut used to toggle no-scripting switch" }, "relaxBlockingMode": { diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/fr/messages.json ublock-origin-1.67.0+dfsg/src/_locales/fr/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/fr/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/fr/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -116,7 +116,7 @@ "description": "English: Click to open the dashboard" }, "popupTipZapper": { - "message": "Entrer en mode Zappeur", + "message": "Entrer en mode Zappeur d'élément", "description": "Tooltip for the element-zapper icon in the popup panel" }, "popupTipPicker": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Créer un rapport", + "message": "Créer un nouveau rapport sur GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Trouver des rapports similaires", + "message": "Trouver des rapports similaires sur GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Pour éviter d'encombrer les contributeurs avec des rapports en double, veuillez vérifier que le problème n'a pas déjà été rapporté.", + "message": "Pour éviter d'encombrer les contributeurs avec des rapports en double, veuillez vérifier que le problème n'a pas déjà été rapporté.\nNote : Cliquer sur le bouton entraînera l'envoi de la page d'origine à GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "La page bloquée souhaite rediriger vers un autre site. Si vous choisissez de continuer, vous vous rendrez à l'adresse suivante : {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Motif du blocage :", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malveillant", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Pisteur", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Douteux", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exporter vers le stockage dans le nuage", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/fy/messages.json ublock-origin-1.67.0+dfsg/src/_locales/fy/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/fy/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/fy/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -40,7 +40,7 @@ "description": "appears as tab name in dashboard" }, "whitelistPageName": { - "message": "Whitelist", + "message": "Fertroude websites", "description": "appears as tab name in dashboard" }, "shortcutsPageName": { @@ -268,7 +268,7 @@ "description": "appears in popup" }, "popupHitDomainCount": { - "message": "{{count}} fan de {{total}}", + "message": "{{count}} fan {{total}}", "description": "appears in popup" }, "popupVersion": { @@ -424,7 +424,7 @@ "description": "Appears at the top of the _3rd-party filters_ pane" }, "3pListsOfBlockedHostsPerListStats": { - "message": "{{used}} gebrûk fan {{total}}", + "message": "{{used}} fan de {{total}} brûkt", "description": "Appears aside each filter list in the _3rd-party filters_ pane" }, "3pAutoUpdatePrompt1": { @@ -808,7 +808,7 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartType": { - "message": "type “{{type}}”", + "message": "type ‘{{type}}’", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartAnyType": { @@ -816,7 +816,7 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartOrigin": { - "message": "fan “{{origin}}”", + "message": "fan ‘{{origin}}’", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartAnyOrigin": { @@ -1195,6 +1195,22 @@ "message": "De blokkearre side wol nei in oare website trochferwize. As jo fierder gean, wurdt de folgjende side oproppen: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reden:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "kweawillich", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "berucht", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Eksportearje nei cloudûnthâld", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/gl/messages.json ublock-origin-1.67.0+dfsg/src/_locales/gl/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/gl/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/gl/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -108,7 +108,7 @@ "description": "For the new mobile-friendly popup design" }, "popupDomainsConnected_v2": { - "message": "Dominos conectados", + "message": "Dominios conectados", "description": "For the new mobile-friendly popup design" }, "popupTipDashboard": { @@ -184,7 +184,7 @@ "description": "Tooltip for the no-scripting per-site switch" }, "popupTipNoScripting2": { - "message": "Preme para volver a activar JavaScript nesta web", + "message": "Preme para volver activar JavaScript nesta web", "description": "Tooltip for the no-scripting per-site switch" }, "popupNoPopups_v2": { @@ -1195,6 +1195,22 @@ "message": "A páxina bloqueada quere redirixir a outra web. Se elixes continuar vas ir directamente a: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Razón:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Daniña", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Rastrexo", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Mala reputación", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exportar ó almacenamento na nube", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/gu/messages.json ublock-origin-1.67.0+dfsg/src/_locales/gu/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/gu/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/gu/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/he/messages.json ublock-origin-1.67.0+dfsg/src/_locales/he/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/he/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/he/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -904,7 +904,7 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "מצא דוחות דומים", + "message": "חיפוש דוחות דומים", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -1195,6 +1195,22 @@ "message": "הדף החסום מבקש לעבור לאתר אחר. אם תחליטו להמשיך, תעברו ישירות ל: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "הסיבה:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "זדוני", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "מעקב", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "מפוקפק", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "ייצא לאחסון ענן", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/hi/messages.json ublock-origin-1.67.0+dfsg/src/_locales/hi/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/hi/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/hi/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -1192,9 +1192,25 @@ "description": "Button text to navigate to the blocked page" }, "docblockedRedirectPrompt": { - "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", + "message": "ब्लॉक किया गया पेज किसी दूसरी साइट पर ले जाना चाहता है. अगर आप आगे बढ़ना चुनते हैं, तो आप सीधे इस लिंक को खोल सकते हैं: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "कारण:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "दुर्भावनापूर्ण", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "ट्रैकर", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "जर्जर", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "क्लाउड स्टोरेज में भेजें", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/hr/messages.json ublock-origin-1.67.0+dfsg/src/_locales/hr/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/hr/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/hr/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -140,11 +140,11 @@ "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoPopups2": { - "message": "Kliknite za ukloniti blokiranje svih pop-up prozora na ovom sajtu", + "message": "Kliknite za ukloniti blokiranje svih pop-up prozora na ovoj stranici", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoLargeMedia": { - "message": "Namjestite blokiranje velikih medijskih elemenata za ovo mjesto", + "message": "Namjestite blokiranje velikih medijskih elemenata za ovu stranicu", "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoLargeMedia1": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Napravi novu prijavu", + "message": "Napravi novu prijavu na GitHub-u", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Nađi slične prijave", + "message": "Nađi slične prijave na GitHub-u", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Kako biste izbjegli opterećivanje volontera duplim prijavama, provjerite nije li problem već prijavljen.", + "message": "Kako biste izbjegli opterećivanje volontera duplim prijavama, provjerite nije li problem već prijavljen. Napomena: klik na gumb uzrokovat će slanje izvorne stranice na GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "Blokirana stranica želi preusmjeriti na drugu stranicu. Ako odlučite nastaviti, otići ćete izravno na: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Razlog:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Zlonamjerno", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Pratioc", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Zloglasno", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Izvezi u pohranu u oblaku", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/hu/messages.json ublock-origin-1.67.0+dfsg/src/_locales/hu/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/hu/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/hu/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -1195,6 +1195,22 @@ "message": "A blokkolt oldal egy másik webhelyre akarja átirányítani. Ha a folytatást választja, akkor közvetlenül ide fog navigálni: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Ok:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Káros", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Nyomkövető", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Rossz hírnevű", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exportálás a felhőszolgáltatásba", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/hy/messages.json ublock-origin-1.67.0+dfsg/src/_locales/hy/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/hy/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/hy/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -1192,9 +1192,25 @@ "description": "Button text to navigate to the blocked page" }, "docblockedRedirectPrompt": { - "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", + "message": "Արգելափակված կայքը ցանկանում է տեղափոխել Ձեզ ուրիշ կայք։ Եթե ցանկանում եք շարունակել, Դուք անմիջապես կտեղափոխվեք {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Արտահանել առ ամպային պահեստ", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/id/messages.json ublock-origin-1.67.0+dfsg/src/_locales/id/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/id/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/id/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Buat laporan baru", + "message": "Buat laporan baru di Github", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Temukan laporan serupa", + "message": "Temukan laporan serupa di Github", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -1060,7 +1060,7 @@ "description": "Shown in the About pane" }, "aboutCDNs": { - "message": "Daftar filter uBO sendiri dihosting secara gratis di CDN berikut:", + "message": "Daftar filter bawaan uBO dihosting secara gratis di CDN berikut:", "description": "Shown in the About pane" }, "aboutCDNsInfo": { @@ -1195,6 +1195,22 @@ "message": "Halaman yang terblokir ingin dialihkan ke situs lain. Jika Anda memilih untuk melanjutkan, Anda akan langsung menuju ke: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Penyebab", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Berbahaya", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Pelacak", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Tidak bisa dipercaya", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Ekspor ke penyimpanan awan", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/it/messages.json ublock-origin-1.67.0+dfsg/src/_locales/it/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/it/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/it/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -28,7 +28,7 @@ "description": "appears as tab name in dashboard" }, "3pPageName": { - "message": "Filtri di terze parti", + "message": "Liste dei filtri", "description": "appears as tab name in dashboard" }, "1pPageName": { @@ -76,7 +76,7 @@ "description": "Message to be read by screen readers" }, "popupPowerSwitchInfo2": { - "message": "Clicca per attivare uBlock₀ in questo sito.", + "message": "Clicca per abilitare uBlock₀ per questo sito.", "description": "Message to be read by screen readers" }, "popupBlockedRequestPrompt": { @@ -1195,6 +1195,22 @@ "message": "La pagina bloccata vuole reindirizzare a un altro sito. Se scegli di procedere, navigherai direttamente a: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Motivo:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Maligno", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Localizzatore", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disdicevole", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Esporta nel cloud", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/ja/messages.json ublock-origin-1.67.0+dfsg/src/_locales/ja/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/ja/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/ja/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -1195,6 +1195,22 @@ "message": "ブロックしたページは別のサイトへリダイレクトしようとしています。続行すると次の URL へ移動します: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "理由:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "悪意のある", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "トラッカー", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "悪い評判", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "クラウドストレージにエクスポートします", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/ka/messages.json ublock-origin-1.67.0+dfsg/src/_locales/ka/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/ka/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/ka/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -68,7 +68,7 @@ "description": "Title for the advanced settings page" }, "popupPowerSwitchInfo": { - "message": "დაწკაპუნება: ამ საიტისთვის uBlock-ის ჩართვა/გამორთვა.\n\nCtrl+დაწკაპუნება: uBlock-ის მხოლოდ ამ გვერდზე გამორთვა.", + "message": "დაწკაპებით: ჩაირთვება/გამოირთვება uBlock ამ საიტზე.\n\nCtrl+დაწკაპებით: გამოირთვება uBlock მხოლოდ ამ გვერდზე.", "description": "English: Click: disable/enable uBlock₀ for this site.\n\nCtrl+click: disable uBlock₀ only on this page." }, "popupPowerSwitchInfo1": { @@ -364,7 +364,7 @@ "description": "English: " }, "settingsWebRTCIPAddressHiddenPrompt": { - "message": "WebRTC-სთვის ხელის შეშლა შიდა IP მისამართის გაჟონვაში", + "message": "WebRTC-ით შიდა IP-მისამართის გამჟღავნების აღკვეთა", "description": "English: " }, "settingPerSiteSwitchGroup": { @@ -388,7 +388,7 @@ "description": "" }, "settingsNoScriptingPrompt": { - "message": "JavaScript-ის გათიშვა", + "message": "გაითიშოს JavaScript", "description": "The default state for the per-site no-scripting switch" }, "settingsNoCSPReportsPrompt": { @@ -536,7 +536,7 @@ "description": "used as a tooltip for error icon beside a list" }, "1pTrustWarning": { - "message": "ფილტრების არიდება არასანდო წყაროებიდან.", + "message": "ნუ დაამატებთ ფილტრებს არასანდო წყაროებიდან.", "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { @@ -944,7 +944,7 @@ "description": "Header of 'Bug report' section in Support pane" }, "supportS4P1": { - "message": "თავად uBlock Origin-ის ხარვეზების მოსახსენებლად, გამოიყენეთ uBlockOrigin/uBlock-issue ხარვეზების აღსარიცხავი. დაგჭირდებათ GitHub-ანგარიში.", + "message": "ხარვეზების მოხსენებისთვის, რომლის წყაროცაა თავად uBlock Origin, გამოიყენეთ uBlockOrigin/uBlock-issue ხარვეზების აღსარიცხავი. დაგჭირდებათ GitHub-ანგარიში.", "description": "First paragraph of 'Bug report' section in Support pane" }, "supportS5H": { @@ -1060,7 +1060,7 @@ "description": "Shown in the About pane" }, "aboutCDNs": { - "message": "uBO-ს კუთვნილი ფილტრები ღიადაა განთავსებული შემდეგ CDN-ებზე:", + "message": "uBO საკუთარ ფილტრებს ღიად ათავსებს მოცემულ CDN-ებზე:", "description": "Shown in the About pane" }, "aboutCDNsInfo": { @@ -1092,7 +1092,7 @@ "description": "Message to display when an error occurred during restore" }, "aboutResetDataConfirm": { - "message": "თქვენ მიერ მითითებული ყველა პარამეტრი წაიშლება და uBlock₀ გაეშვება ხელახლა.\n\nნამდვილად გსურთ uBlock₀-ის ნაგულისხმევ პარამეტრებზე დაბრუნება?", + "message": "თქვენ მიერ მითითებული ყველა პარამეტრი წაიშლება და uBlock₀ გაეშვება ხელახლა.\n\nნამდვილად გსურთ დაბრუნდეს uBlock₀ ნაგულისხმევ პარამეტრებზე?", "description": "Message asking user to confirm reset" }, "errorCantConnectTo": { @@ -1195,6 +1195,22 @@ "message": "ეს შეზღუდული გვერდი ცდილობს სხვა საიტზე გადაყვანას. თუ განაგრძობთ, პირდაპირ გაიხსნება: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "მიზეზი:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "მავნებელი", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "მეთვალყურე", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "სახელგატეხილი", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "ღრუბლოვან საცავში შენახვა", "description": "tooltip" @@ -1272,7 +1288,7 @@ "description": "Label for keyboard shortcut used to toggle cosmetic filtering" }, "toggleJavascript": { - "message": "JavaScript-ის ჩამრთველი", + "message": "JavaScript – გადამრთველი", "description": "Label for keyboard shortcut used to toggle no-scripting switch" }, "relaxBlockingMode": { diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/kk/messages.json ublock-origin-1.67.0+dfsg/src/_locales/kk/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/kk/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/kk/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Бұлтты жадқа экспорттау", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/kn/messages.json ublock-origin-1.67.0+dfsg/src/_locales/kn/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/kn/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/kn/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -8,7 +8,7 @@ "description": "this will be in the Chrome web store: must be 132 characters or less" }, "dashboardName": { - "message": "uBlock₀ - ಡ್ಯಾಶ್ಬೋರ್ಡ", + "message": "uBlock₀ - ಡ್ಯಾಶ್ಬೋರ್ಡು", "description": "English: uBlock₀ — Dashboard" }, "dashboardUnsavedWarning": { @@ -148,7 +148,7 @@ "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoLargeMedia1": { - "message": "Click to block large media elements on this site", + "message": "ಈ ಸೈಟ್‌ಗಾಗಿ ದೊಡ್ಡ ಮಾಧ್ಯಮ ಅಂಶಗಳ ನಿರ್ಬಂಧಿಸುವಿಕೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ಕ್ಲಿಕ್ ಮಾಡಿ", "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoLargeMedia2": { @@ -160,11 +160,11 @@ "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoCosmeticFiltering1": { - "message": "Click to disable cosmetic filtering on this site", + "message": "ಈ ಸೈಟ್‌ನಲ್ಲಿ ಕಾಸ್ಮೆಟಿಕ್ ಫಿಲ್ಟರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಕ್ಲಿಕ್ ಮಾಡಿ.", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoCosmeticFiltering2": { - "message": "Click to enable cosmetic filtering on this site", + "message": "ಈ ಸೈಟ್‌ನಲ್ಲಿ ಕಾಸ್ಮೆಟಿಕ್ ಫಿಲ್ಟರಿಂಗ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ಕ್ಲಿಕ್ ಮಾಡಿ.", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoRemoteFonts": { @@ -616,7 +616,7 @@ "description": "English: label for sort option." }, "rulesSortByType": { - "message": "Rule type", + "message": "ನಿಯಮದ ಪ್ರಕಾರ", "description": "English: a sort option for list of rules." }, "rulesSortBySource": { @@ -748,7 +748,7 @@ "description": "Small header to identify the 'Details' pane for a specific logger entry" }, "loggerEntryDetailsFilter": { - "message": "Filter", + "message": "ಫಿಲ್ಟರ್", "description": "Label to identify a filter field" }, "loggerEntryDetailsFilterList": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/ko/messages.json ublock-origin-1.67.0+dfsg/src/_locales/ko/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/ko/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/ko/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -1195,6 +1195,22 @@ "message": "차단된 페이지에서 다른 사이트로 이동하려 합니다. 계속하시면, {{url}} 주소로 바로 이동합니다.", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "사유:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "악성", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "추적기", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "낮은 평판", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "클라우드 저장소로 내보내기", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/lt/messages.json ublock-origin-1.67.0+dfsg/src/_locales/lt/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/lt/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/lt/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Eksportuoti į nuotolinę saugyklą", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/lv/messages.json ublock-origin-1.67.0+dfsg/src/_locales/lv/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/lv/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/lv/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -20,7 +20,7 @@ "description": "Label for button to prevent navigating away from unsaved changes" }, "dashboardUnsavedWarningIgnore": { - "message": "Ignorēt", + "message": "Neņemt vērā", "description": "Label for button to ignore unsaved changes" }, "settingsPageName": { @@ -76,7 +76,7 @@ "description": "Message to be read by screen readers" }, "popupPowerSwitchInfo2": { - "message": "Klikšķināt, lai šai vietnei ieslēgtu uBlock₀.", + "message": "Klikšķināt, lai šajā vietnē iespējotu uBlock₀.", "description": "Message to be read by screen readers" }, "popupBlockedRequestPrompt": { @@ -340,7 +340,7 @@ "description": "Section for controlling user interface appearance" }, "settingsThemeLabel": { - "message": "Motīvs", + "message": "Izskats", "description": "Label for checkbox to enable a custom dark theme" }, "settingsThemeAccent0Label": { @@ -448,11 +448,11 @@ "description": "Describes the purpose of the 'Parse and enforce cosmetic filters' feature." }, "3pIgnoreGenericCosmeticFilters": { - "message": "Ignorēt vispārīgos kosmētiskos filtrus", + "message": "Neņemt vērā vispārīgos kosmētiskos aizturētājus", "description": "This will cause uBO to ignore all generic cosmetic filters." }, "3pIgnoreGenericCosmeticFiltersInfo": { - "message": "

    Vispārīgie kosmētikas filtri ir kosmētikas filtri, kurus paredzēts piemērot visās tīmekļvietnēs.

    Lai gan uBlock ₀ darbojas efektīvi, vispārīgie kosmētikas filtri dažās tīmekļa lapās var ievērojami noslogot atmiņu un centrālo procesoru.

    Šīs opcijas izmantošana samazinās vispārīgo kosmētikas filtru izmantotās atmiņas un procesora noslodzi kā arī samazinās paša uBlock₀ izmantoto atmiņu.

    Ieteicams izmantot zemas veiktspējas ierīcēm.", + "message": "Vispārīgie kosmētiskie aizturētāji ir tādi kosmētiskie aizturētāji, kurus paredzēts pielietot visās tīmekļvietnēs. Šīs iespējas iespējošana novērsīs tīmekļa lapām pievienoto atmiņas un CPU virstēriņu kā vispārīgo kosmētisko aizturētāju apstrādāšanas iznākumu.\n\nIr ieteicams iespējot šo iespēju mazāk jaudīgās ierīcēs.", "description": "Describes the purpose of the 'Ignore generic cosmetic filters' feature." }, "3pSuspendUntilListsAreLoaded": { @@ -508,11 +508,11 @@ "description": "Filter lists section name" }, "3pImport": { - "message": "Importēt…", + "message": "Ievietot…", "description": "The label for the checkbox used to import external filter lists" }, "3pExternalListsHint": { - "message": "Vienu URL katrā rindiņā. Rindiņas, kuras sākas ar ‘!’ tiks ignorētas. Nederīgs URL tiks ignorēts bez brīdinājuma.", + "message": "Viens URL katrā rindā. Nederīgi URL netiks ņemti vērā.", "description": "Short information about how to use the textarea to import external filter lists by URL" }, "3pExternalListObsolete": { @@ -552,7 +552,7 @@ "description": "Button in the 'My filters' pane" }, "1pExport": { - "message": "Eksportēt…", + "message": "Izgūt…", "description": "Button in the 'My filters' pane" }, "1pExportFilename": { @@ -592,11 +592,11 @@ "description": "Will discard manually-edited content and exit manual-edit mode" }, "rulesImport": { - "message": "Importēt no faila…", + "message": "Ievietot no datnes…", "description": "" }, "rulesExport": { - "message": "Eksportēt uz failu", + "message": "Izgūt datnē…", "description": "Button in the 'My rules' pane" }, "rulesDefaultFileName": { @@ -636,7 +636,7 @@ "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { - "message": "Eksportēt…", + "message": "Izgūt…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExportFilename": { @@ -932,7 +932,7 @@ "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { - "message": "Svarīgi: ir jāizvairas no līdzīgu aizturētāju izmantošanas vienlaicīgi ar uBlock Origin, jo tas var radīt aizturēšanas kļūmes noteiktās vietnēs.", + "message": "Svarīgi: ir jāizvairās no līdzīgu aizturētāju izmantošanas vienlaicīgi ar uBlock Origin, jo tas var radīt aizturēšanas kļūmes noteiktās vietnēs.", "description": "Second paragraph of 'Filter issues' section in Support pane" }, "supportS3P3": { @@ -956,7 +956,7 @@ "description": "First paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS5P2": { - "message": "Svarīgi: iespējami privāta vai sensitīva informācija pēc noklusējuma tiek izņemta. Aizvākta informācija var apgrūtināt sarežģījuma atrisināšanu.", + "message": "Svarīgi: iespējami privāta vai jūtīga informācija pēc noklusējuma tiek izņemta. Aizvākta informācija var apgrūtināt sarežģījuma atrisināšanu.", "description": "Second paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS6H": { @@ -1195,6 +1195,22 @@ "message": "Aizturētā lapa veic pārvirzīšanu uz citu vietni. Ja izvēlēsies turpināt, nonāksi uzreiz šeit: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Iemesls:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Ļaunprātīgas darbības", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Izsekotājs", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Slikta slava", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Eksports uz mākoņdatu glabātuvi", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/mk/messages.json ublock-origin-1.67.0+dfsg/src/_locales/mk/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/mk/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/mk/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -1195,6 +1195,22 @@ "message": "Блокираната страница сака да ве пренасочи на друга веб-страница. Ако изберете да продолжите, директно ќе навигирате до: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Извези во облачно складиште", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/ml/messages.json ublock-origin-1.67.0+dfsg/src/_locales/ml/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/ml/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/ml/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "ക്ലൌഡ് സ്റ്റോറേജിലേക്ക് എക്സ്പോര്‍ട്ട്‌ ചെയ്യുക", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/mr/messages.json ublock-origin-1.67.0+dfsg/src/_locales/mr/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/mr/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/mr/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/ms/messages.json ublock-origin-1.67.0+dfsg/src/_locales/ms/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/ms/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/ms/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Eksport ke storan awan", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/nb/messages.json ublock-origin-1.67.0+dfsg/src/_locales/nb/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/nb/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/nb/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -484,7 +484,7 @@ "description": "Filter lists section name" }, "3pGroupSocial": { - "message": "Sosiale mediers moduler", + "message": "Sosiale moduler", "description": "Filter lists section name" }, "3pGroupCookies": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Opprett ny rapport", + "message": "Opprett ny rapport på GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Finn lignende rapporter", + "message": "Finn lignende rapporter på GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "For å unngå å belaste frivillige med duplikate rapporter, kontroller at problemet ikke allerede er rapportert.", + "message": "For å unngå å belaste de frivillige med dobbeltrapporter, må du kontrollere at problemet ikke allerede har blitt rapportert. Noter: ved å klikke på knappen vil sidens opprinnelse bli sendt til GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1012,7 +1012,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { - "message": "Leads to badware, phishing", + "message": "Fører til skadelig programvare og/eller phishing", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { @@ -1192,9 +1192,25 @@ "description": "Button text to navigate to the blocked page" }, "docblockedRedirectPrompt": { - "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", + "message": "Den blokkerte siden ønsker å omdirigere til et annet nettsted. Hvis du velger å fortsette, vil du navigere direkte til: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Grunn:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Ondsinnet", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Sporer", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Tvilsom", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Eksporter til nettlagring", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/nl/messages.json ublock-origin-1.67.0+dfsg/src/_locales/nl/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/nl/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/nl/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -720,7 +720,7 @@ "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltinEventful": { - "message": "afwisselend", + "message": "belangrijk", "description": "A keyword in the built-in row filtering expression: all items corresponding to uBO doing something (blocked, allowed, redirected, etc.)" }, "loggerRowFiltererBuiltinBlocked": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Nieuwe melding maken", + "message": "Nieuwe melding op GitHub maken", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Soortgelijke meldingen zoeken", + "message": "Soortgelijke meldingen op GitHub zoeken", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Controleer of het probleem niet eerder is gemeld om te voorkomen dat vrijwilligers met dubbele meldingen worden belast.", + "message": "Controleer of het probleem niet eerder is gemeld om te voorkomen dat vrijwilligers met dubbele meldingen worden belast. Noot: op de knop klikken zorgt ervoor dat de oorsprong van de pagina naar GitHub wordt verzonden.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "De geblokkeerde pagina wil u omleiden naar een andere website. Als u doorgaat, navigeert u rechtstreeks naar: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reden:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "kwaadwillend", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "berucht", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exporteren naar cloudopslag", "description": "tooltip" @@ -1236,7 +1252,7 @@ "description": "" }, "contextMenuBlockElementInFrame": { - "message": "Element in frame blokkeren…", + "message": "Element in deelvenster blokkeren…", "description": "An entry in the browser's contextual menu" }, "contextMenuSubscribeToList": { diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/oc/messages.json ublock-origin-1.67.0+dfsg/src/_locales/oc/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/oc/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/oc/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "La pagina blocada vòl redirigir cap a un autre site. Se causissètz de perseguir, aniretz dirèctament a : {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/pa/messages.json ublock-origin-1.67.0+dfsg/src/_locales/pa/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/pa/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/pa/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "ਕਲਾਉਡ ਸਟੋਰੇਜ਼ ਉੱਤੇ ਐਕਸਪੋਰਟ ਕਰੋ", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/pl/messages.json ublock-origin-1.67.0+dfsg/src/_locales/pl/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/pl/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/pl/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -484,7 +484,7 @@ "description": "Filter lists section name" }, "3pGroupSocial": { - "message": "Widżety społecznościowe", + "message": "Widety społecznościowe", "description": "Filter lists section name" }, "3pGroupCookies": { @@ -1195,6 +1195,22 @@ "message": "Zablokowana strona chce przekierować na inną witrynę. Jeśli zdecydujesz się kontynuować, przejdziesz bezpośrednio do: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Powód:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "złośliwa", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "śledząca", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "podejrzana", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Eksportuj do chmury", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/pt_BR/messages.json ublock-origin-1.67.0+dfsg/src/_locales/pt_BR/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/pt_BR/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/pt_BR/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Finalmente, um bloqueador eficiente. Com baixo uso de CPU e memória.", + "message": "Até que enfim, um bloqueador eficiente. Com baixo uso da CPU e da memória.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "dashboardName": { @@ -72,11 +72,11 @@ "description": "English: Click: disable/enable uBlock₀ for this site.\n\nCtrl+click: disable uBlock₀ only on this page." }, "popupPowerSwitchInfo1": { - "message": "Clique pra desativar o uBlock₀ neste site.\n\nCtrl+clique pra desativar o uBlock₀ só nesta página.", + "message": "Clique para desativar o uBlock₀ neste site.\n\nCtrl+clique para desativar o uBlock₀ só nesta página.", "description": "Message to be read by screen readers" }, "popupPowerSwitchInfo2": { - "message": "Clique pra ativar o uBlock₀ neste site.", + "message": "Clique para ativar o uBlock₀ neste site.", "description": "Message to be read by screen readers" }, "popupBlockedRequestPrompt": { @@ -100,11 +100,11 @@ "description": "English: or" }, "popupBlockedOnThisPage_v2": { - "message": "Bloqueado(s) nesta página", + "message": "Bloqueios nesta página", "description": "For the new mobile-friendly popup design" }, "popupBlockedSinceInstall_v2": { - "message": "Bloqueado(s) desde a instalação", + "message": "Bloqueios desde a instalação", "description": "For the new mobile-friendly popup design" }, "popupDomainsConnected_v2": { @@ -116,7 +116,7 @@ "description": "English: Click to open the dashboard" }, "popupTipZapper": { - "message": "Entrar no modo do elemento zapper", + "message": "Entrar no modo de remoção de elementos", "description": "Tooltip for the element-zapper icon in the popup panel" }, "popupTipPicker": { @@ -128,7 +128,7 @@ "description": "Tooltip used for the logger icon in the panel" }, "popupTipReport": { - "message": "Reportar um problema com este site da web", + "message": "Reportar um problema com este site", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipNoPopups": { @@ -144,7 +144,7 @@ "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoLargeMedia": { - "message": "Alternar o bloqueio de grandes elementos de mídia neste site", + "message": "Habilitar o bloqueio de grandes elementos de mídia neste site", "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoLargeMedia1": { @@ -156,7 +156,7 @@ "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoCosmeticFiltering": { - "message": "Alternar a filtragem cosmética neste site", + "message": "Habilitar a filtragem cosmética neste site", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoCosmeticFiltering1": { @@ -168,7 +168,7 @@ "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoRemoteFonts": { - "message": "Alternar o bloqueio de fontes remotas neste site", + "message": "Habilitar o bloqueio de fontes remotas neste site", "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoRemoteFonts1": { @@ -176,15 +176,15 @@ "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoRemoteFonts2": { - "message": "Clique pra não mais bloquear fontes remotas neste site", + "message": "Clique para deixar de bloquear fontes remotas neste site", "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoScripting1": { - "message": "Clique pra desativar o JavaScript neste site", + "message": "Clique para desativar o JavaScript neste site", "description": "Tooltip for the no-scripting per-site switch" }, "popupTipNoScripting2": { - "message": "Clique pra não mais desativar o JavaScript neste site", + "message": "Clique para deixar de desativar o JavaScript neste site", "description": "Tooltip for the no-scripting per-site switch" }, "popupNoPopups_v2": { @@ -244,7 +244,7 @@ "description": "" }, "popup3pPassiveRulePrompt": { - "message": "CSS/Imagens de terceiros", + "message": "CSS/imagens de terceiros", "description": "" }, "popupInlineScriptRulePrompt": { @@ -356,11 +356,11 @@ "description": "Checkbox to let user access advanced, technical features" }, "settingsPrefetchingDisabledPrompt": { - "message": "Desativar pré-busca (pra impedir quaisquer requisições de redes bloqueadas)", + "message": "Desativar pré-solicitações (para impedir qualquer solicitação de rede a recursos bloqueados)", "description": "English: " }, "settingsHyperlinkAuditingDisabledPrompt": { - "message": "Desativar auditoria dos hyperlinks", + "message": "Desativar auditoria de hyperlinks", "description": "English: " }, "settingsWebRTCIPAddressHiddenPrompt": { @@ -392,7 +392,7 @@ "description": "The default state for the per-site no-scripting switch" }, "settingsNoCSPReportsPrompt": { - "message": "Bloquear relatórios do CSP", + "message": "Bloquear relatórios de CSPs", "description": "background information: https://github.com/gorhill/uBlock/issues/3150" }, "settingsUncloakCnamePrompt": { @@ -424,7 +424,7 @@ "description": "Appears at the top of the _3rd-party filters_ pane" }, "3pListsOfBlockedHostsPerListStats": { - "message": "{{used}} usados de {{total}}", + "message": "{{used}} usados dos {{total}}", "description": "Appears aside each filter list in the _3rd-party filters_ pane" }, "3pAutoUpdatePrompt1": { @@ -444,7 +444,7 @@ "description": "English: Parse and enforce Adblock+ element hiding filters." }, "3pParseAllABPHideFiltersInfo": { - "message": "Os filtros cosméticos servem pra esconder elementos de uma página da web os quais são considerados um incômodo visual e os quais não podem ser bloqueados pelas engines de filtragem baseadas em requisições de rede.", + "message": "Os filtros cosméticos servem para ocultar elementos em uma página os quais são considerados um incômodo visual e os quais não podem ser bloqueados pelos motores de filtragem baseadas em solicitações de rede.", "description": "Describes the purpose of the 'Parse and enforce cosmetic filters' feature." }, "3pIgnoreGenericCosmeticFilters": { @@ -452,7 +452,7 @@ "description": "This will cause uBO to ignore all generic cosmetic filters." }, "3pIgnoreGenericCosmeticFiltersInfo": { - "message": "Os filtros cosméticos genéricos são aqueles filtros cosméticos os quais são destinados a serem aplicados em todos os sites da web. Ativar esta opção eliminará a sobrecarga da memória e da CPU adicionada as páginas da web como um resultado de lidar com filtros cosméticos genéricos.\n\nÉ recomendado ativar esta opção em dispositivos menos poderosos.", + "message": "Os filtros cosméticos genéricos são aqueles filtros cosméticos os quais são destinados a serem aplicados em todos os sites. Ativar esta opção eliminará a sobrecarga da memória e da CPU adicionada as páginas como um resultado de lidar com filtros cosméticos genéricos.\n\nÉ recomendado ativar esta opção em dispositivos mais lentos.", "description": "Describes the purpose of the 'Ignore generic cosmetic filters' feature." }, "3pSuspendUntilListsAreLoaded": { @@ -536,7 +536,7 @@ "description": "used as a tooltip for error icon beside a list" }, "1pTrustWarning": { - "message": "Não adicionar filtros de fontes não confiáveis.", + "message": "Não adicione filtros de fontes não confiáveis.", "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { @@ -548,7 +548,7 @@ "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { - "message": "Importar e anexar", + "message": "Importar e anexar…", "description": "Button in the 'My filters' pane" }, "1pExport": { @@ -576,7 +576,7 @@ "description": "This will remove all temporary rules" }, "rulesCommit": { - "message": "Submeter", + "message": "Confirmar", "description": "This will persist temporary rules" }, "rulesEdit": { @@ -596,7 +596,7 @@ "description": "" }, "rulesExport": { - "message": "Exportar pro arquivo", + "message": "Exportar para um arquivo…", "description": "Button in the 'My rules' pane" }, "rulesDefaultFileName": { @@ -608,7 +608,7 @@ "description": "English: List of your dynamic filtering rules." }, "rulesFormatHint": { - "message": "Regras da sintaxe: ação do tipo de destino da origem (documentação completa).", + "message": "Regras de sintaxe: fonte destino tipo ação (documentação completa).", "description": "English: dynamic rule syntax and full documentation." }, "rulesSort": { @@ -628,11 +628,11 @@ "description": "English: a sort option for list of rules." }, "whitelistPrompt": { - "message": "As diretivas dos sites confiáveis ditam em quais páginas da web o uBlock Origin deve ser desativado. Uma entrada por linha. ", + "message": "As diretivas dos sites confiáveis ditam em quais páginas o uBlock Origin deve ser desativado. Uma entrada por linha. ", "description": "A concise description of the 'Trusted sites' pane." }, "whitelistImport": { - "message": "Importar e anexar", + "message": "Importar e anexar…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { @@ -680,11 +680,11 @@ "description": "Tooltip for the reload button in the logger page" }, "loggerDomInspectorTip": { - "message": "Alternar o inspetor do DOM", + "message": "Habilitar o inspetor de DOM", "description": "Tooltip for the DOM inspector button in the logger page" }, "loggerPopupPanelTip": { - "message": "Alternar o painel do pop-up", + "message": "Habilitar o painel pop-up", "description": "Tooltip for the popup panel button in the logger page" }, "loggerInfoTip": { @@ -696,7 +696,7 @@ "description": "Tooltip for the eraser in the logger page; used to blank the content of the logger" }, "loggerPauseTip": { - "message": "Pausar coletor (descartar todos os dados que entram)", + "message": "Pausar coletor (descartar todos os dados futuros)", "description": "Tooltip for the pause button in the logger page" }, "loggerUnpauseTip": { @@ -704,7 +704,7 @@ "description": "Tooltip for the play button in the logger page" }, "loggerRowFiltererButtonTip": { - "message": "Alternar filtragem do coletor", + "message": "Habilitar filtragem do coletor", "description": "Tooltip for the row filterer button in the logger page" }, "logFilterPrompt": { @@ -768,7 +768,7 @@ "description": "Label to identify a root context field (typically a hostname)" }, "loggerEntryDetailsPartyness": { - "message": "Grupos", + "message": "Originário/de terceiros", "description": "Label to identify a field providing partyness information" }, "loggerEntryDetailsType": { @@ -796,7 +796,7 @@ "description": "Small header to identify the static filtering section" }, "loggerStaticFilteringSentence": { - "message": "{{action}} requisições da rede de {{type}} {{br}}cujo endereço de URL corresponde {{url}} {{br}}e o qual se origina em {{origin}},{{br}}{{importance}} há um filtro de exceção correspondente.", + "message": "{{action}} solicitações de rede do tipo {{type}} {{br}}onde o endereço da URL corresponde a {{url}} {{br}} e que origina de {{origin}},{{br}}{{importance}} há um filtro de exceção correspondente.", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartBlock": { @@ -840,7 +840,7 @@ "description": "Message to show when a filter cannot be found in any filter lists" }, "loggerSettingDiscardPrompt": { - "message": "As entradas do coletor que não preencherem todas as três condições abaixo serão descartadas automaticamente:", + "message": "Os registros que não preencherem todas as três condições abaixo serão descartados automaticamente:", "description": "Logger setting: A sentence to describe the purpose of the settings below" }, "loggerSettingPerEntryMaxAge": { @@ -852,11 +852,11 @@ "description": "A logger setting" }, "loggerSettingPerTabMaxEntries": { - "message": "Preservar no máximo {{input}} entradas por aba", + "message": "Preservar no máximo {{input}} registros por aba", "description": "A logger setting" }, "loggerSettingPerEntryLineCount": { - "message": "Usar {{input}} linhas por entrada no modo expandido verticalmente", + "message": "Usar {{input}} linhas por registro no modo expandido verticalmente", "description": "A logger setting" }, "loggerSettingHideColumnsPrompt": { @@ -876,7 +876,7 @@ "description": "A label for the context column" }, "loggerSettingHideColumnPartyness": { - "message": "{{input}} Grupos", + "message": "{{input}} Originário/de terceiros", "description": "A label for the partyness column" }, "loggerExportFormatList": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Criar um novo relatório", + "message": "Criar um novo relatório no GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Achar relatórios similares", + "message": "Achar relatórios similares no GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -924,19 +924,19 @@ "description": "First paragraph of 'Questions and support' section in Support pane" }, "supportS3H": { - "message": "Problemas com o filtro/o site da web está quebrado", + "message": "Problemas com filtros/o site não funciona", "description": "Header of 'Filter issues' section in Support pane" }, "supportS3P1": { - "message": "Reporte problemas com os filtros em sites específicos da web no rastreador de problemas do uBlockOrigin/uAssets. Requer uma conta no GitHub.", + "message": "Reporte problemas com os filtros em sites específicos no rastreador de problemas do uBlockOrigin/uAssets. Uma conta do GitHub é necessária.", "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { - "message": "Importante: Evite usar outros bloqueadores com propósito similar junto do uBlock Origin pois isto pode causar problemas com filtros em sites da web específicos.", + "message": "Importante: Evite usar outros bloqueadores junto com o uBlock Origin pois isto pode causar problemas com filtros em sites específicos.", "description": "Second paragraph of 'Filter issues' section in Support pane" }, "supportS3P3": { - "message": "Dicas: Certifique-se que sua lista de filtros está atualizada. O coletor é a ferramenta primária pra diagnosticar problemas relacionados com os filtros.", + "message": "Dicas: Certifique-se que suas listas de filtros estão atualizadas. O coletor é a ferramenta principal para diagnosticar problemas relacionados aos filtros.", "description": "Third paragraph of 'Filter issues' section in Support pane" }, "supportS4H": { @@ -944,7 +944,7 @@ "description": "Header of 'Bug report' section in Support pane" }, "supportS4P1": { - "message": "Reporte problemas com o próprio uBlock Origin no uBlockOrigin/uBlock-issuerastreador de problemas. Requer uma conta no GitHub.", + "message": "Reporte problemas com o próprio uBlock Origin no rastreador de problemas do uBlockOrigin/uBlock-issue. Uma conta do GitHub é necessária.", "description": "First paragraph of 'Bug report' section in Support pane" }, "supportS5H": { @@ -956,7 +956,7 @@ "description": "First paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS5P2": { - "message": "Atenção: Informações potencialmente privadas ou sensíveis são eliminadas por padrão. As informações eliminadas podem tornar mais difícil resolver um problema.", + "message": "Importante: Informações potencialmente privadas ou sensíveis são eliminadas por padrão. As informações eliminadas podem dificultar a resolução de um problema.", "description": "Second paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS6H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Pra evitar sobrecarregar os voluntários com relatórios duplicados por favor certifique-se que o problema já não foi reportado.", + "message": "Para evitar sobrecarregar os voluntários com relatórios duplicados por favor verifique se o problema já não foi reportado. Observação: clicar no botão fará com que a origem da página seja enviada ao GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -984,15 +984,15 @@ "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { - "message": "— Escolha uma entrada —", + "message": "— Selecione um tipo —", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { - "message": "Mostra os anúncios ou restos de anúncios", + "message": "Mostra anúncios ou restos de anúncios", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "Tem sobreposições ou outros incômodos", + "message": "Tem sobreposições ou outras perturbações", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { @@ -1004,7 +1004,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "Funciona mal quando o uBlock Origin está ativado", + "message": "Não funciona direito quando o uBlock Origin está ativado", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { @@ -1016,7 +1016,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { - "message": "Rotula a página da web como \"NSFW\" (\"Não é Seguro no Trabalho\")", + "message": "Rotular a página da web como \"NSFW\" (\"Não é Seguro no Trabalho\")", "description": "A checkbox to use for NSFW sites" }, "supportRedact": { @@ -1060,15 +1060,15 @@ "description": "Shown in the About pane" }, "aboutCDNs": { - "message": "As próprias listas de filtros do uBO estão hospedadas gratuitamente nos seguintes CDNs: ", + "message": "As próprias listas de filtros do uBO estão hospedadas gratuitamente nas seguintes CDNs: ", "description": "Shown in the About pane" }, "aboutCDNsInfo": { - "message": "Um CDN escolhido aleatoriamente é usado quando uma lista de filtros precisa ser atualizada", + "message": "Uma CDN é escolhida automaticamente quando uma lista de filtros precisa ser atualizada.", "description": "Shown in the About pane" }, "aboutBackupDataButton": { - "message": "Fazer backup no arquivo", + "message": "Fazer backup para arquivo", "description": "Text for button to create a backup of all settings" }, "aboutBackupFilename": { @@ -1080,7 +1080,7 @@ "description": "English: Restore from file..." }, "aboutResetDataButton": { - "message": "Resetar para as configurações padrão…", + "message": "Redefinir pras configurações padrão…", "description": "English: Reset to default settings..." }, "aboutRestoreDataConfirm": { @@ -1092,7 +1092,7 @@ "description": "Message to display when an error occurred during restore" }, "aboutResetDataConfirm": { - "message": "Todas as suas configurações serão removidas, e o uBlock₀ reiniciará.\n\nResetar o uBlock₀ para as configurações de fábrica?", + "message": "Todas as suas configurações serão removidas, e o uBlock₀ reiniciará.\n\nRedefinir o uBlock₀ para as configurações de fábrica?", "description": "Message asking user to confirm reset" }, "errorCantConnectTo": { @@ -1136,7 +1136,7 @@ "description": "Firefox/Fennec-specific: Show Dashboard" }, "showNetworkLogButton": { - "message": "Mostrar Coletor", + "message": "Mostrar coletor", "description": "Firefox/Fennec-specific: Show Logger" }, "fennecMenuItemBlockingOff": { @@ -1192,9 +1192,25 @@ "description": "Button text to navigate to the blocked page" }, "docblockedRedirectPrompt": { - "message": "A página bloqueada quer redirecionar pra outro site. Se você escolher prosseguir você navegará diretamente para: {{url}}", + "message": "A página bloqueada deseja redirecionar para outro site. Se você escolher continuar, você navegará diretamente para: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Motivo:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicioso", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Rastreador", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Má reputação", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exportar pro armazenamento na nuvem", "description": "tooltip" @@ -1240,7 +1256,7 @@ "description": "An entry in the browser's contextual menu" }, "contextMenuSubscribeToList": { - "message": "Subscrever na lista de filtros... ", + "message": "Inscrever-se na lista de filtros...", "description": "An entry in the browser's contextual menu" }, "contextMenuTemporarilyAllowLargeMediaElements": { @@ -1248,7 +1264,7 @@ "description": "A context menu entry, present when large media elements have been blocked on the current site" }, "contextMenuViewSource": { - "message": "Visualizar código fonte…", + "message": "Visualizar código-fonte…", "description": "A context menu entry, to view the source code of the target resource" }, "shortcutCapturePlaceholder": { @@ -1272,7 +1288,7 @@ "description": "Label for keyboard shortcut used to toggle cosmetic filtering" }, "toggleJavascript": { - "message": "Alternar JavaScript", + "message": "Habilitar JavaScript", "description": "Label for keyboard shortcut used to toggle no-scripting switch" }, "relaxBlockingMode": { @@ -1304,7 +1320,7 @@ "description": "Summary of number of errors as reported by the linter " }, "unprocessedRequestTooltip": { - "message": "Não conseguiu filtrar apropriadamente na inicialização do navegador. Recarregue a página pra garantir a filtragem apropriada.", + "message": "Não foi possível filtrar apropriadamente na inicialização do navegador. Recarregue a página para garantir a filtragem apropriada.", "description": "A warning which will appear in the popup panel if needed" }, "dummy": { diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/pt_PT/messages.json ublock-origin-1.67.0+dfsg/src/_locales/pt_PT/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/pt_PT/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/pt_PT/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Finalmente, um bloqueador eficiente. Leve na CPU e memória.", + "message": "Finalmente, um bloqueador eficiente. Leve para a CPU e a memória.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "dashboardName": { @@ -16,7 +16,7 @@ "description": "A warning in the dashboard when navigating away from unsaved changes" }, "dashboardUnsavedWarningStay": { - "message": "Permanecer", + "message": "Permanecer aqui", "description": "Label for button to prevent navigating away from unsaved changes" }, "dashboardUnsavedWarningIgnore": { @@ -48,7 +48,7 @@ "description": "appears as tab name in dashboard" }, "statsPageName": { - "message": "uBlock₀ — Registador", + "message": "uBlock₀ — Registo", "description": "Title for the logger window" }, "aboutPageName": { @@ -116,7 +116,7 @@ "description": "English: Click to open the dashboard" }, "popupTipZapper": { - "message": "Entrar no modo \"zapper\" de elemento", + "message": "Entrar no modo de remoção rápida de elemento", "description": "Tooltip for the element-zapper icon in the popup panel" }, "popupTipPicker": { @@ -124,7 +124,7 @@ "description": "English: Enter element picker mode" }, "popupTipLog": { - "message": "Abrir o registador", + "message": "Abrir o registo", "description": "Tooltip used for the logger icon in the panel" }, "popupTipReport": { @@ -536,7 +536,7 @@ "description": "used as a tooltip for error icon beside a list" }, "1pTrustWarning": { - "message": "Não adicione filtros de fontes não confiáveis.", + "message": "Não adicione filtros de fontes não fidedignas.", "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { @@ -688,23 +688,23 @@ "description": "Tooltip for the popup panel button in the logger page" }, "loggerInfoTip": { - "message": "uBlock Origin wiki: O registador", + "message": "uBlock Origin wiki: O registo", "description": "Tooltip for the top-right info label in the logger page" }, "loggerClearTip": { - "message": "Limpar registador", + "message": "Limpar registo", "description": "Tooltip for the eraser in the logger page; used to blank the content of the logger" }, "loggerPauseTip": { - "message": "Pausar registador (descartar todos os dados a receber)", + "message": "Pausar registo (descartar todos os dados a receber)", "description": "Tooltip for the pause button in the logger page" }, "loggerUnpauseTip": { - "message": "Retomar registador", + "message": "Retomar registo", "description": "Tooltip for the play button in the logger page" }, "loggerRowFiltererButtonTip": { - "message": "Alternar filtragem do registador", + "message": "Alternar filtragem do registo", "description": "Tooltip for the row filterer button in the logger page" }, "logFilterPrompt": { @@ -712,7 +712,7 @@ "description": "Placeholder string for logger output filtering input field" }, "loggerRowFiltererBuiltinTip": { - "message": "Opções de filtragem do registador", + "message": "Opções de filtragem do registo", "description": "Tooltip for the button to bring up logger output filtering options" }, "loggerRowFiltererBuiltinNot": { @@ -840,7 +840,7 @@ "description": "Message to show when a filter cannot be found in any filter lists" }, "loggerSettingDiscardPrompt": { - "message": "Entradas do registador que não preenchem todas as três condições abaixo serão automaticamente descartadas:", + "message": "Entradas do registo que não preenchem todas as três condições abaixo serão automaticamente descartadas:", "description": "Logger setting: A sentence to describe the purpose of the settings below" }, "loggerSettingPerEntryMaxAge": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Criar novo relatório", + "message": "Criar novo relatório no GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Encontrar relatórios semelhantes", + "message": "Encontrar relatórios semelhantes no GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -936,7 +936,7 @@ "description": "Second paragraph of 'Filter issues' section in Support pane" }, "supportS3P3": { - "message": "Dicas: certifique-se de que as suas listas de filtros estão atualizadas. O registador é a ferramenta principal para diagnosticar problemas relacionados com filtros.", + "message": "Dicas: certifique-se de que as suas listas de filtros estão atualizadas. O registo é a ferramenta principal para diagnosticar problemas relacionados com filtros.", "description": "Third paragraph of 'Filter issues' section in Support pane" }, "supportS4H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Para evitar sobrecarregar os voluntários com relatórios duplicados, por favor verifique se o problema ainda não foi relatado.", + "message": "Para evitar sobrecarregar os voluntários com relatórios duplicados, verifique se o problema ainda não foi relatado. Nota: clicar no botão fará com que a origem da página seja enviada para o GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1136,7 +1136,7 @@ "description": "Firefox/Fennec-specific: Show Dashboard" }, "showNetworkLogButton": { - "message": "Mostrar registador", + "message": "Mostrar registo", "description": "Firefox/Fennec-specific: Show Logger" }, "fennecMenuItemBlockingOff": { @@ -1195,6 +1195,22 @@ "message": "A página bloqueada pretende redirecionar para outro site. Se optar por proceder, navegará diretamente para: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Motivo:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicioso", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Rastreador", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Má reputação", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exportar para a nuvem", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/ro/messages.json ublock-origin-1.67.0+dfsg/src/_locales/ro/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/ro/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/ro/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -488,7 +488,7 @@ "description": "Filter lists section name" }, "3pGroupCookies": { - "message": "Cookie notices", + "message": "Notificări privind cookie-urile", "description": "Filter lists section name" }, "3pGroupAnnoyances": { @@ -540,11 +540,11 @@ "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { - "message": "Enable my custom filters", + "message": "Activați filtrele mele personalizate", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { - "message": "Allow custom filters requiring trust", + "message": "Permiteți filtre personalizate care necesită încredere", "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { @@ -624,7 +624,7 @@ "description": "English: a sort option for list of rules." }, "rulesSortByDestination": { - "message": "Destinaţia", + "message": "Destinație", "description": "English: a sort option for list of rules." }, "whitelistPrompt": { @@ -840,7 +840,7 @@ "description": "Message to show when a filter cannot be found in any filter lists" }, "loggerSettingDiscardPrompt": { - "message": "Intrările din jurnal care nu îndeplinesc cele trei condiții de mai jos vor fi respinse automat:", + "message": "Intrările în registrul de logare care nu îndeplinesc toate cele trei condiții de mai jos vor fi automat eliminate.", "description": "Logger setting: A sentence to describe the purpose of the settings below" }, "loggerSettingPerEntryMaxAge": { @@ -1012,7 +1012,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { - "message": "Leads to badware, phishing", + "message": "Duce la programe dăunătoare, phishing", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { @@ -1192,9 +1192,25 @@ "description": "Button text to navigate to the blocked page" }, "docblockedRedirectPrompt": { - "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", + "message": "Pagina blocată dorește să redirecționeze către un alt site. Dacă alegeți să continuați, veți naviga direct către: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exportă către stocarea în cloud", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/ru/messages.json ublock-origin-1.67.0+dfsg/src/_locales/ru/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/ru/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/ru/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Создать новый отчет", + "message": "Создать новый отчёт в GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Найти похожие отчеты", + "message": "Найти похожие отчёты в GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Чтобы не обременять волонтеров дублированными отчетами, пожалуйста, убедитесь, что о данной проблеме еще не сообщали", + "message": "Чтобы не обременять добровольцев повторяющимися отчётами, пожалуйста, убедитесь, что об этой проблеме ещё не сообщали. Примечание: щелчок по кнопке приведёт к отправке адреса посещенной страницы GitHub'у.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "Заблокированная страница собирается перенаправить вас на другой сайт. Если вы решите продолжить, вы перейдете непосредственно на: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Причина:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Вредоносная активность", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Трекер", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Сомнительное содержание", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Экспорт в облачное хранилище", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/si/messages.json ublock-origin-1.67.0+dfsg/src/_locales/si/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/si/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/si/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -48,7 +48,7 @@ "description": "appears as tab name in dashboard" }, "statsPageName": { - "message": "uBlock₀ — Logger", + "message": "යූබ්ලොක්₀ — ලඝුර", "description": "Title for the logger window" }, "aboutPageName": { @@ -60,7 +60,7 @@ "description": "appears as tab name in dashboard" }, "assetViewerPageName": { - "message": "uBlock₀ — Asset viewer", + "message": "යූබ්ලොක්₀ — වත්කම් දක්වනය", "description": "Title for the asset viewer page" }, "advancedSettingsPageName": { @@ -68,11 +68,11 @@ "description": "Title for the advanced settings page" }, "popupPowerSwitchInfo": { - "message": "Click: disable/enable uBlock₀ for this site.\n\nCtrl+click: disable uBlock₀ only on this page.", + "message": "ඔබන්න: මෙම අඩවියට යූබ්ලොක්₀ අබල/සබල කරන්න.\n\nCtrl+ඔබන්න: මෙම පිටුවට පමණක් යූබ්ලොක්₀ අබල කරන්න.", "description": "English: Click: disable/enable uBlock₀ for this site.\n\nCtrl+click: disable uBlock₀ only on this page." }, "popupPowerSwitchInfo1": { - "message": "Click to disable uBlock₀ for this site.\n\nCtrl+click to disable uBlock₀ only on this page.", + "message": "මෙම අඩවියට යූබ්ලොක්₀ අබල/සබල කිරීමට ඔබන්න.\n\nමෙම පිටුවට පමණක් යූබ්ලොක්₀ අබල කිරීමට Ctrl+ඔබන්න.", "description": "Message to be read by screen readers" }, "popupPowerSwitchInfo2": { @@ -116,15 +116,15 @@ "description": "English: Click to open the dashboard" }, "popupTipZapper": { - "message": "Enter element zapper mode", + "message": "මූලද්‍රව්‍ය zapper ප්‍රකාරයට ඇතුළු වන්න", "description": "Tooltip for the element-zapper icon in the popup panel" }, "popupTipPicker": { - "message": "Enter element picker mode", + "message": "මූලද්‍රව්‍ය තෝරක ප්‍රකාරයට ඇතුළු වන්න", "description": "English: Enter element picker mode" }, "popupTipLog": { - "message": "Open the logger", + "message": "ලඝුර අරින්න", "description": "Tooltip used for the logger icon in the panel" }, "popupTipReport": { @@ -132,51 +132,51 @@ "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipNoPopups": { - "message": "Toggle the blocking of all popups for this site", + "message": "මෙම අඩවිය සඳහා සියලු උත්පතන අවහිර කිරීම ටොගල් කරන්න", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoPopups1": { - "message": "Click to block all popups on this site", + "message": "මෙම අඩවියේ ඇති සියලුම උත්පතන අවහිර කිරීමට ක්ලික් කරන්න.", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoPopups2": { - "message": "Click to no longer block all popups on this site", + "message": "මෙම අඩවියේ ඇති සියලුම උත්පතන තවදුරටත් අවහිර නොකිරීමට ක්ලික් කරන්න.", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoLargeMedia": { - "message": "Toggle the blocking of large media elements for this site", + "message": "මෙම අඩවිය සඳහා විශාල මාධ්‍ය අංග අවහිර කිරීම ටොගල් කරන්න.", "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoLargeMedia1": { - "message": "Click to block large media elements on this site", + "message": "මෙම අඩවියේ විශාල මාධ්‍ය අංග අවහිර කිරීමට ක්ලික් කරන්න.", "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoLargeMedia2": { - "message": "Click to no longer block large media elements on this site", + "message": "මෙම අඩවියේ විශාල මාධ්‍ය අංග තවදුරටත් අවහිර නොකිරීමට ක්ලික් කරන්න.", "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoCosmeticFiltering": { - "message": "Toggle cosmetic filtering for this site", + "message": "මෙම අඩවිය සඳහා රූපලාවන්‍ය පෙරහන ටොගල් කරන්න", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoCosmeticFiltering1": { - "message": "Click to disable cosmetic filtering on this site", + "message": "මෙම අඩවියේ රූපලාවන්‍ය පෙරහන් අක්‍රිය කිරීමට ක්ලික් කරන්න.", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoCosmeticFiltering2": { - "message": "Click to enable cosmetic filtering on this site", + "message": "මෙම අඩවියේ රූපලාවන්‍ය පෙරහන් සක්‍රීය කිරීමට ක්ලික් කරන්න.", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoRemoteFonts": { - "message": "Toggle the blocking of remote fonts for this site", + "message": "මෙම අඩවිය සඳහා දුරස්ථ අකුරු අවහිර කිරීම ටොගල් කරන්න", "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoRemoteFonts1": { - "message": "Click to block remote fonts on this site", + "message": "මෙම අඩවියේ දුරස්ථ අකුරු අවහිර කිරීමට ක්ලික් කරන්න.", "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoRemoteFonts2": { - "message": "Click to no longer block remote fonts on this site", + "message": "මෙම අඩවියේ දුරස්ථ අකුරු තවදුරටත් අවහිර නොකිරීමට ක්ලික් කරන්න.", "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoScripting1": { @@ -196,7 +196,7 @@ "description": "Caption for the no-large-media per-site switch" }, "popupNoCosmeticFiltering_v2": { - "message": "Cosmetic filtering", + "message": "රූපලාවන්‍ය පෙරහන", "description": "Caption for the no-cosmetic-filtering per-site switch" }, "popupNoRemoteFonts_v2": { @@ -220,15 +220,15 @@ "description": "Tooltip when hovering the top-most cell of the global-rules column." }, "popupTipLocalRules": { - "message": "Local rules: this column is for rules which apply to the current site only.\nLocal rules override global rules.", + "message": "දේශීය නීති: මෙම තීරුව වත්මන් අඩවියට පමණක් අදාළ වන නීති සඳහා වේ.\nදේශීය නීති ගෝලීය නීති අභිබවා යයි.", "description": "Tooltip when hovering the top-most cell of the local-rules column." }, "popupTipSaveRules": { - "message": "Click to make your changes permanent.", + "message": "ඔබගේ වෙනස්කම් ස්ථිර කිරීමට ක්ලික් කරන්න.", "description": "Tooltip when hovering over the padlock in the dynamic filtering pane." }, "popupTipRevertRules": { - "message": "Click to revert your changes.", + "message": "ඔබගේ වෙනස්කම් ප්‍රතිවර්තනය කිරීමට ක්ලික් කරන්න.", "description": "Tooltip when hovering over the eraser in the dynamic filtering pane." }, "popupAnyRulePrompt": { @@ -268,7 +268,7 @@ "description": "appears in popup" }, "popupHitDomainCount": { - "message": "{{count}} out of {{total}}", + "message": "{{total}}න් {{count}}", "description": "appears in popup" }, "popupVersion": { @@ -288,7 +288,7 @@ "description": "English: Create" }, "pickerPick": { - "message": "Pick", + "message": "තෝරන්න", "description": "English: Pick" }, "pickerQuit": { @@ -304,7 +304,7 @@ "description": "English: header for a type of filter in the element picker dialog" }, "pickerCosmeticFilters": { - "message": "Cosmetic filters", + "message": "රූපලාවන්‍ය පෙරහන්", "description": "English: Cosmetic filters" }, "pickerCosmeticFiltersHint": { @@ -316,7 +316,7 @@ "description": "An entry in the browser's contextual menu" }, "settingsCollapseBlockedPrompt": { - "message": "Hide placeholders of blocked elements", + "message": "අවහිර කළ මූලද්‍රව්‍යවල ස්ථාන දරන්නන් සඟවන්න", "description": "English: Hide placeholders of blocked elements" }, "settingsIconBadgePrompt": { @@ -324,7 +324,7 @@ "description": "English: Show the number of blocked requests on the icon" }, "settingsTooltipsPrompt": { - "message": "Disable tooltips", + "message": "මෙවලම් ඉඟි අක්‍රීය කරන්න", "description": "A checkbox in the Settings pane" }, "settingsContextMenuPrompt": { @@ -344,7 +344,7 @@ "description": "Label for checkbox to enable a custom dark theme" }, "settingsThemeAccent0Label": { - "message": "Custom accent color", + "message": "අභිරුචි උදාත්ත වර්ණය", "description": "Label for checkbox to pick an accent color" }, "settingsCloudStorageEnabledPrompt": { @@ -356,7 +356,7 @@ "description": "Checkbox to let user access advanced, technical features" }, "settingsPrefetchingDisabledPrompt": { - "message": "Disable pre-fetching (to prevent any connection for blocked network requests)", + "message": "පූර්ව-ලබා ගැනීම අක්‍රීය කරන්න (අවහිර කළ ජාල ඉල්ලීම් සඳහා කිසිදු සම්බන්ධතාවයක් වැළැක්වීමට)", "description": "English: " }, "settingsHyperlinkAuditingDisabledPrompt": { @@ -364,19 +364,19 @@ "description": "English: " }, "settingsWebRTCIPAddressHiddenPrompt": { - "message": "Prevent WebRTC from leaking local IP addresses", + "message": "දේශීය IP ලිපින කාන්දු වීම WebRTC වලක්වන්න", "description": "English: " }, "settingPerSiteSwitchGroup": { - "message": "Default behavior", + "message": "පෙරනිමි හැසිරීම", "description": "" }, "settingPerSiteSwitchGroupSynopsis": { - "message": "These default behaviors can be overridden on a per-site basis", + "message": "මෙම පෙරනිමි හැසිරීම් එක් එක් අඩවියට අනුව අභිබවා යා හැක.", "description": "" }, "settingsNoCosmeticFilteringPrompt": { - "message": "Disable cosmetic filtering", + "message": "රූපලාවන්‍ය පෙරහන අක්‍රීය කරන්න", "description": "" }, "settingsNoLargeMediaPrompt": { @@ -396,7 +396,7 @@ "description": "background information: https://github.com/gorhill/uBlock/issues/3150" }, "settingsUncloakCnamePrompt": { - "message": "Uncloak canonical names", + "message": "කැනොනිකල් නම් ඉවත් කරන්න", "description": "background information: https://github.com/uBlockOrigin/uBlock-issues/issues/1513" }, "settingsAdvanced": { @@ -420,15 +420,15 @@ "description": "English: Last backup:" }, "3pListsOfBlockedHostsPrompt": { - "message": "{{netFilterCount}} network filters + {{cosmeticFilterCount}} cosmetic filters from:", + "message": "{{netFilterCount}} ජාල පෙරහන් + {{cosmeticFilterCount}} රූපලාවන්‍ය පෙරහන්:", "description": "Appears at the top of the _3rd-party filters_ pane" }, "3pListsOfBlockedHostsPerListStats": { - "message": "{{used}} used out of {{total}}", + "message": "{{total}} න් {{used}} ක් භාවිතා කර ඇත", "description": "Appears aside each filter list in the _3rd-party filters_ pane" }, "3pAutoUpdatePrompt1": { - "message": "Auto-update filter lists", + "message": "පෙරහන් ලැයිස්තු ස්වයංක්‍රීයව යාවත්කාලීන කරන්න", "description": "A checkbox in the _3rd-party filters_ pane" }, "3pUpdateNow": { @@ -436,27 +436,27 @@ "description": "A button in the in the _3rd-party filters_ pane" }, "3pPurgeAll": { - "message": "Purge all caches", + "message": "සියලුම හැඹිලි ඉවත් කරන්න", "description": "A button in the in the _3rd-party filters_ pane" }, "3pParseAllABPHideFiltersPrompt1": { - "message": "Parse and enforce cosmetic filters", + "message": "රූපලාවන්‍ය පෙරහන් විග්‍රහ කර බලාත්මක කරන්න", "description": "English: Parse and enforce Adblock+ element hiding filters." }, "3pParseAllABPHideFiltersInfo": { - "message": "Cosmetic filters serve to hide elements in a web page which are deemed to be a visual nuisance, and which can't be blocked by the network request-based filtering engines.", + "message": "රූපලාවන්‍ය පෙරහන් යනු වෙබ් පිටුවක දෘශ්‍ය කරදරයක් ලෙස සලකනු ලබන සහ ජාල ඉල්ලීම් මත පදනම් වූ පෙරහන් එන්ජින් මගින් අවහිර කළ නොහැකි අංග සැඟවීමට සේවය කරයි.", "description": "Describes the purpose of the 'Parse and enforce cosmetic filters' feature." }, "3pIgnoreGenericCosmeticFilters": { - "message": "Ignore generic cosmetic filters", + "message": "සාමාන්‍ය රූපලාවන්‍ය පෙරහන් නොසලකා හරින්න.", "description": "This will cause uBO to ignore all generic cosmetic filters." }, "3pIgnoreGenericCosmeticFiltersInfo": { - "message": "Generic cosmetic filters are those cosmetic filters which are meant to apply on all web sites. Enabling this option will eliminate the memory and CPU overhead added to web pages as a result of handling generic cosmetic filters.\n\nIt is recommended to enable this option on less powerful devices.", + "message": "සාමාන්‍ය රූපලාවන්‍ය පෙරහන් යනු සියලුම වෙබ් අඩවිවල යෙදීමට අදහස් කරන රූපලාවන්‍ය පෙරහන් වේ. මෙම විකල්පය සක්‍රීය කිරීමෙන් සාමාන්‍ය රූපලාවන්‍ය පෙරහන් හැසිරවීමේ ප්‍රතිඵලයක් ලෙස වෙබ් පිටුවලට එකතු වන මතකය සහ CPU උඩිස් බර ඉවත් කරනු ඇත.\n\nඅඩු බලවත් උපාංගවල මෙම විකල්පය සක්‍රීය කිරීම නිර්දේශ කෙරේ.", "description": "Describes the purpose of the 'Ignore generic cosmetic filters' feature." }, "3pSuspendUntilListsAreLoaded": { - "message": "Suspend network activity until all filter lists are loaded", + "message": "සියලුම පෙරහන් ලැයිස්තු පූරණය වන තුරු ජාල ක්‍රියාකාරකම් අත්හිටුවන්න.", "description": "A checkbox in the 'Filter lists' pane" }, "3pListsOfBlockedHostsHeader": { @@ -480,11 +480,11 @@ "description": "Filter lists section name" }, "3pGroupMalware": { - "message": "Malware protection, security", + "message": "අනිෂ්ට මෘදුකාංග ආරක්ෂාව, ආරක්ෂාව", "description": "Filter lists section name" }, "3pGroupSocial": { - "message": "Social widgets", + "message": "සමාජ විජට්", "description": "Filter lists section name" }, "3pGroupCookies": { @@ -492,15 +492,15 @@ "description": "Filter lists section name" }, "3pGroupAnnoyances": { - "message": "Annoyances", + "message": "කරදර", "description": "Filter lists section name" }, "3pGroupMultipurpose": { - "message": "Multipurpose", + "message": "බහුකාර්ය", "description": "Filter lists section name" }, "3pGroupRegions": { - "message": "Regions, languages", + "message": "කලාප, භාෂා", "description": "Filter lists section name" }, "3pGroupCustom": { @@ -512,11 +512,11 @@ "description": "The label for the checkbox used to import external filter lists" }, "3pExternalListsHint": { - "message": "One URL per line. Invalid URLs will be silently ignored.", + "message": "පේළියකට එක් URL එකක් බැගින්. අවලංගු URL නිහඬව නොසලකා හරිනු ලැබේ.", "description": "Short information about how to use the textarea to import external filter lists by URL" }, "3pExternalListObsolete": { - "message": "Out of date.", + "message": "කල් ඉකුත් වී ඇත.", "description": "used as a tooltip for the out-of-date icon beside a list" }, "3pViewContent": { @@ -524,7 +524,7 @@ "description": "used as a tooltip for eye icon beside a list" }, "3pLastUpdate": { - "message": "Last update: {{ago}}.\nClick to force an update.", + "message": "අවසන් යාවත්කාලීන කිරීම: {{ago}}.\nයාවත්කාලීන කිරීමට බල කිරීමට ක්ලික් කරන්න.", "description": "used as a tooltip for the clock icon beside a list" }, "3pUpdating": { @@ -532,23 +532,23 @@ "description": "used as a tooltip for the spinner icon beside a list" }, "3pNetworkError": { - "message": "A network error prevented the resource from being updated.", + "message": "ජාල දෝෂයක් නිසා සම්පත යාවත්කාලීන වීම වැළැක්විණි.", "description": "used as a tooltip for error icon beside a list" }, "1pTrustWarning": { - "message": "Do not add filters from untrusted sources.", + "message": "විශ්වාස නොකළ මූලාශ්‍රවලින් පෙරහන් එක් නොකරන්න.", "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { - "message": "Enable my custom filters", + "message": "මගේ අභිරුචි පෙරහන් සක්‍රීය කරන්න", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { - "message": "Allow custom filters requiring trust", + "message": "විශ්වාසය අවශ්‍ය අභිරුචි පෙරහන් වලට ඉඩ දෙන්න.", "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { - "message": "Import and append…", + "message": "…ආයාත කර එකතු කරන්න", "description": "Button in the 'My filters' pane" }, "1pExport": { @@ -556,7 +556,7 @@ "description": "Button in the 'My filters' pane" }, "1pExportFilename": { - "message": "my-ublock-static-filters_{{datetime}}.txt", + "message": "මගේ-ublock-static-filters_{{datetime}}.txt", "description": "English: my-ublock-static-filters_{{datetime}}.txt" }, "1pApplyChanges": { @@ -564,7 +564,7 @@ "description": "English: Apply changes" }, "rulesPermanentHeader": { - "message": "Permanent rules", + "message": "ස්ථිර නීති", "description": "header" }, "rulesTemporaryHeader": { @@ -576,7 +576,7 @@ "description": "This will remove all temporary rules" }, "rulesCommit": { - "message": "Commit", + "message": "කැප කරන්න", "description": "This will persist temporary rules" }, "rulesEdit": { @@ -604,11 +604,11 @@ "description": "default file name to use" }, "rulesHint": { - "message": "List of your dynamic filtering rules.", + "message": "ඔබගේ ගතික පෙරහන් නීති ලැයිස්තුව.", "description": "English: List of your dynamic filtering rules." }, "rulesFormatHint": { - "message": "Rule syntax: source destination type action (full documentation).", + "message": "රීති වාක්‍ය ඛණ්ඩය: මූලාශ්‍ර ගමනාන්ත වර්ගය ක්‍රියාව (සම්පූර්ණ ලියකියවිලි).", "description": "English: dynamic rule syntax and full documentation." }, "rulesSort": { @@ -624,15 +624,15 @@ "description": "English: a sort option for list of rules." }, "rulesSortByDestination": { - "message": "Destination", + "message": "ගමනාන්තය", "description": "English: a sort option for list of rules." }, "whitelistPrompt": { - "message": "The trusted site directives dictate on which web pages uBlock Origin should be disabled. One entry per line.", + "message": "විශ්වාසදායක අඩවි නියෝග මඟින් uBlock Origin අක්‍රිය කළ යුත්තේ කුමන වෙබ් පිටු මතද යන්න නියම කරයි. පේළියකට එක් ඇතුළත් කිරීමක් පමණි.", "description": "A concise description of the 'Trusted sites' pane." }, "whitelistImport": { - "message": "Import and append…", + "message": "…ආයාත කර එකතු කරන්න", "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { @@ -668,55 +668,55 @@ "description": "Appears in the logger's tab selector" }, "logBehindTheScene": { - "message": "Tabless", + "message": "මේස", "description": "Pretty name for behind-the-scene network requests" }, "loggerCurrentTab": { - "message": "Current tab", + "message": "වත්මන් ටැබය", "description": "Appears in the logger's tab selector" }, "loggerReloadTip": { - "message": "Reload the tab content", + "message": "ටැබ් අන්තර්ගතය නැවත පූරණය කරන්න", "description": "Tooltip for the reload button in the logger page" }, "loggerDomInspectorTip": { - "message": "Toggle the DOM inspector", + "message": "DOM පරීක්ෂක ටොගල් කරන්න", "description": "Tooltip for the DOM inspector button in the logger page" }, "loggerPopupPanelTip": { - "message": "Toggle the popup panel", + "message": "උත්පතන පැනලය ටොගල් කරන්න", "description": "Tooltip for the popup panel button in the logger page" }, "loggerInfoTip": { - "message": "uBlock Origin wiki: The logger", + "message": "uBlock සම්භවය විකි: ලොගර්", "description": "Tooltip for the top-right info label in the logger page" }, "loggerClearTip": { - "message": "Clear logger", + "message": "ලොගර් හිස් කරන්න", "description": "Tooltip for the eraser in the logger page; used to blank the content of the logger" }, "loggerPauseTip": { - "message": "Pause logger (discard all incoming data)", + "message": "ලොගර් විරාම කරන්න (එන සියලුම දත්ත ඉවතලන්න)", "description": "Tooltip for the pause button in the logger page" }, "loggerUnpauseTip": { - "message": "Unpause logger", + "message": "ලොගර් විරාම නොකරන්න", "description": "Tooltip for the play button in the logger page" }, "loggerRowFiltererButtonTip": { - "message": "Toggle logger filtering", + "message": "ලොගර් පෙරහන ටොගල් කරන්න", "description": "Tooltip for the row filterer button in the logger page" }, "logFilterPrompt": { - "message": "filter logger content", + "message": "පෙරහන් ලොගර් අන්තර්ගතය", "description": "Placeholder string for logger output filtering input field" }, "loggerRowFiltererBuiltinTip": { - "message": "Logger filtering options", + "message": "ලොගර් පෙරහන් විකල්ප", "description": "Tooltip for the button to bring up logger output filtering options" }, "loggerRowFiltererBuiltinNot": { - "message": "Not", + "message": "නැහැ", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltinEventful": { @@ -768,7 +768,7 @@ "description": "Label to identify a root context field (typically a hostname)" }, "loggerEntryDetailsPartyness": { - "message": "Partyness", + "message": "සාද ගතිය", "description": "Label to identify a field providing partyness information" }, "loggerEntryDetailsType": { @@ -796,7 +796,7 @@ "description": "Small header to identify the static filtering section" }, "loggerStaticFilteringSentence": { - "message": "{{action}} network requests of {{type}} {{br}}which URL address matches {{url}} {{br}}and which originates {{origin}},{{br}}{{importance}} there is a matching exception filter.", + "message": "{{action}} ජාල ඉල්ලීම් {{type}} {{br}}වන URL ලිපිනය {{url}} {{br}}ට ගැලපෙන අතර {{origin}}ට ආරම්භ වේ,{{br}}{{importance}} ට ගැලපෙන ව්‍යතිරේක පෙරහනක් ඇත.", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartBlock": { @@ -820,43 +820,43 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartAnyOrigin": { - "message": "from anywhere", + "message": "ඕනෑම තැනක සිට", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartNotImportant": { - "message": "except when", + "message": "විට හැර", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartImportant": { - "message": "even if", + "message": "විට දී වුවත්", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringFinderSentence1": { - "message": "Static filter {{filter}} found in:", + "message": "ස්ථිතික පෙරහන {{filter}} හමු වූයේ:", "description": "Below this sentence, the filter list(s) in which the filter was found" }, "loggerStaticFilteringFinderSentence2": { - "message": "Static filter could not be found in any of the currently enabled filter lists", + "message": "දැනට සක්‍රිය කර ඇති කිසිදු පෙරහන් ලැයිස්තුවක ස්ථිතික පෙරහන සොයාගත නොහැකි විය.", "description": "Message to show when a filter cannot be found in any filter lists" }, "loggerSettingDiscardPrompt": { - "message": "Logger entries which do not fulfill all three conditions below will be automatically discarded:", + "message": "පහත කොන්දේසි තුනම සපුරා නොමැති ලොගර් ඇතුළත් කිරීම් ස්වයංක්‍රීයව ඉවත දමනු ලැබේ:", "description": "Logger setting: A sentence to describe the purpose of the settings below" }, "loggerSettingPerEntryMaxAge": { - "message": "Preserve entries from the last {{input}} minutes", + "message": "අවසාන මිනිත්තු {{input}} වලින් ඇතුළත් කිරීම් සුරකින්න", "description": "A logger setting" }, "loggerSettingPerTabMaxLoads": { - "message": "Preserve at most {{input}} page loads per tab", + "message": "ටැබ් එකකට උපරිම වශයෙන් {{input}} පිටු පූරණ සංරක්ෂණය කරන්න", "description": "A logger setting" }, "loggerSettingPerTabMaxEntries": { - "message": "Preserve at most {{input}} entries per tab", + "message": "ටැබ් එකකට උපරිම වශයෙන් {{input}} ඇතුළත් කිරීම් සංරක්ෂණය කරන්න", "description": "A logger setting" }, "loggerSettingPerEntryLineCount": { - "message": "Use {{input}} lines per entry in vertically expanded mode", + "message": "සිරස් අතට පුළුල් කළ ප්‍රකාරයේදී ඇතුළත් කිරීමකට {{input}} රේඛා භාවිතා කරන්න.", "description": "A logger setting" }, "loggerSettingHideColumnsPrompt": { @@ -872,15 +872,15 @@ "description": "A label for the filter or rule column" }, "loggerSettingHideColumnContext": { - "message": "{{input}} Context", + "message": "{{input}} සන්දර්භය", "description": "A label for the context column" }, "loggerSettingHideColumnPartyness": { - "message": "{{input}} Partyness", + "message": "{{input}} සාද ස්වභාවය", "description": "A label for the partyness column" }, "loggerExportFormatList": { - "message": "List", + "message": "ලැයිස්තුව", "description": "Label for radio-button to pick export format" }, "loggerExportFormatTable": { @@ -888,11 +888,11 @@ "description": "Label for radio-button to pick export format" }, "loggerExportEncodePlain": { - "message": "Plain", + "message": "සරල", "description": "Label for radio-button to pick export text format" }, "loggerExportEncodeMarkdown": { - "message": "Markdown", + "message": "මාර්ක්ඩවුන්", "description": "Label for radio-button to pick export text format" }, "supportOpenButton": { @@ -912,7 +912,7 @@ "description": "Header of 'Documentation' section in Support pane" }, "supportS1P1": { - "message": "Read the documentation at uBlock/wiki to learn about all of uBlock Origin's features.", + "message": "uBlock Origin හි සියලුම විශේෂාංග ගැන ඉගෙන ගැනීමට uBlock/wiki හි ඇති ලේඛන කියවන්න.", "description": "First paragraph of 'Documentation' section in Support pane" }, "supportS2H": { @@ -920,23 +920,23 @@ "description": "Header of 'Questions and support' section in Support pane" }, "supportS2P1": { - "message": "Answers to questions and other kinds of help support is provided on the subreddit /r/uBlockOrigin.", + "message": "ප්‍රශ්නවලට පිළිතුරු සහ අනෙකුත් ආකාරයේ උපකාර සහාය /r/uBlockOriginයන උප රෙඩිට් එකෙන් සපයනු ලැබේ.", "description": "First paragraph of 'Questions and support' section in Support pane" }, "supportS3H": { - "message": "Filter issues/website is broken", + "message": "පෙරහන් ගැටළු/වෙබ් අඩවිය බිඳ වැටී ඇත", "description": "Header of 'Filter issues' section in Support pane" }, "supportS3P1": { - "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", + "message": "නිශ්චිත වෙබ් අඩවි සමඟ පෙරහන් ගැටළු uBlockOrigin/uAssets ගැටළු ට්රැකර්වෙත වාර්තා කරන්න. GitHub ගිණුමක් අවශ්‍යයි.", "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { - "message": "Important: Avoid using other similarly-purposed blockers along with uBlock Origin, as this may cause filter issues on specific websites.", + "message": "වැදගත්: uBlock Origin සමඟ සමාන අරමුණු සහිත වෙනත් අවහිර කරන්නන් භාවිතා කිරීමෙන් වළකින්න, මන්ද මෙය නිශ්චිත වෙබ් අඩවි වල පෙරහන් ගැටළු ඇති කළ හැකිය.", "description": "Second paragraph of 'Filter issues' section in Support pane" }, "supportS3P3": { - "message": "Tips: Be sure your filter lists are up to date. The logger is the primary tool to diagnose filter-related issues.", + "message": "ඉඟි: ඔබගේ පෙරහන් ලැයිස්තු යාවත්කාලීනව ඇති බවට වග බලා ගන්න. පෙරහන් ආශ්‍රිත ගැටළු හඳුනා ගැනීම සඳහා ලොගර් මූලික මෙවලම වේ.", "description": "Third paragraph of 'Filter issues' section in Support pane" }, "supportS4H": { @@ -944,39 +944,39 @@ "description": "Header of 'Bug report' section in Support pane" }, "supportS4P1": { - "message": "Report issues with uBlock Origin itself to the uBlockOrigin/uBlock-issue issue tracker. Requires a GitHub account.", + "message": "uBlock Origin සමඟ ඇති ගැටළු uBlockOrigin/uBlock-issue ගැටළු ට්‍රැකර්වෙත වාර්තා කරන්න. GitHub ගිණුමක් අවශ්‍යයි.", "description": "First paragraph of 'Bug report' section in Support pane" }, "supportS5H": { - "message": "Troubleshooting Information", + "message": "දෝශ නිරාකරණ තොරතුරු", "description": "Header of 'Troubleshooting Information' section in Support pane" }, "supportS5P1": { - "message": "Below is technical information that might be useful when volunteers are trying to help you solve a problem.", + "message": "ස්වේච්ඡා සේවකයන් ගැටලුවක් විසඳීමට ඔබට උදව් කිරීමට උත්සාහ කරන විට ප්‍රයෝජනවත් විය හැකි තාක්ෂණික තොරතුරු පහත දැක්වේ.", "description": "First paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS5P2": { - "message": "Important: Potentially private or sensitive information is redacted by default. Redacted information may make it more difficult to solve a problem.", + "message": "වැදගත්: පුද්ගලික හෝ සංවේදී තොරතුරු පෙරනිමියෙන් සංස්කරණය කරනු ලැබේ. සංස්කරණය කරන ලද තොරතුරු ගැටළුවක් විසඳීම වඩාත් අපහසු කළ හැකිය.", "description": "Second paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS6H": { - "message": "Report a filter issue", + "message": "පෙරහන් ගැටළුවක් වාර්තා කරන්න", "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "අනුපිටපත් වාර්තා සමඟ ස්වේච්ඡා සේවකයින්ට බරක් වීම වළක්වා ගැනීම සඳහා, කරුණාකර ගැටළුව දැනටමත් වාර්තා කර නොමැති බව තහවුරු කරගන්න. සටහන: බොත්තම ක්ලික් කිරීමෙන් පිටුවේ මූලාරම්භය GitHub වෙත යවනු ලැබේ.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { - "message": "Filter lists are updated daily. Be sure your issue has not already been addressed in the most recent filter lists.", + "message": "පෙරහන් ලැයිස්තු දිනපතා යාවත්කාලීන වේ. ඔබගේ ගැටලුව මෑත කාලීන පෙරහන් ලැයිස්තු වල දැනටමත් විසඳා නොමැති බවට වග බලා ගන්න.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S2": { - "message": "Verify that the issue still exists after reloading the problematic webpage.", + "message": "ගැටළු සහගත වෙබ් පිටුව නැවත පූරණය කිරීමෙන් පසුවද ගැටලුව පවතින බව තහවුරු කරන්න.", "description": "A paragraph in the filter issue reporter section" }, "supportS6URL": { - "message": "Address of the web page:", + "message": "වියමන පිටුවේ ලිපිනය:", "description": "Label for the URL of the page" }, "supportS6Select1": { @@ -984,39 +984,39 @@ "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { - "message": "-- Pick an entry --", + "message": "-- නිවේශිතයක් තෝරන්න --", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { - "message": "Shows ads or ad leftovers", + "message": "දැන්වීම් හෝ දැන්වීම් ඉතිරි කොටස් පෙන්වයි", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "Has overlays or other nuisances", + "message": "උඩැතිරි හෝ වෙනත් කරදර ඇති", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { - "message": "Detects uBlock Origin", + "message": "යූබ්ලොක් ඔරිජින් හඳුනා ගනියි", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { - "message": "Has privacy-related issues", + "message": "පෞද්ගලිකත්‍වය ආශ්‍රිත ගැටළු තිබේ", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "Malfunctions when uBlock Origin is enabled", + "message": "uBlock Origin සක්‍රීය කර ඇති විට සිදුවන අක්‍රමිකතා", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { - "message": "Opens unwanted tabs or windows", + "message": "අනවශ්‍ය පටිති හෝ කවුළු අරියි", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { - "message": "Leads to badware, phishing", + "message": "නරක මෘදුකාංග, තතුබෑම් වලට මග පාදයි", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { - "message": "Label the web page as “NSFW” (“Not Safe For Work”)", + "message": "වෙබ් පිටුව “NSFW” ලෙස ලේබල් කරන්න (“වැඩ සඳහා ආරක්ෂිත නොවේ”)", "description": "A checkbox to use for NSFW sites" }, "supportRedact": { @@ -1056,15 +1056,15 @@ "description": "Link text to uBO's own filter lists repo" }, "aboutDependencies": { - "message": "External dependencies (GPLv3-compatible):", + "message": "බාහිර පරායත්ත (GPLv3-අනුකූල):", "description": "Shown in the About pane" }, "aboutCDNs": { - "message": "uBO's own filter lists are freely hosted on the following CDNs:", + "message": "uBO හි පෙරහන් ලැයිස්තු පහත CDNsමත නිදහසේ සත්කාරකත්වය දරයි:", "description": "Shown in the About pane" }, "aboutCDNsInfo": { - "message": "A randomly picked CDN is used when a filter list needs to be updated.", + "message": "පෙරහන් ලැයිස්තුවක් යාවත්කාලීන කිරීමට අවශ්‍ය වූ විට අහඹු ලෙස තෝරාගත් CDN එකක් භාවිතා වේ.", "description": "Shown in the About pane" }, "aboutBackupDataButton": { @@ -1072,7 +1072,7 @@ "description": "Text for button to create a backup of all settings" }, "aboutBackupFilename": { - "message": "my-ublock-backup_{{datetime}}.txt", + "message": "මාගේ-ublock-උපස්ථය_{{datetime}}.txt", "description": "English: my-ublock-backup_{{datetime}}.txt" }, "aboutRestoreDataButton": { @@ -1084,15 +1084,15 @@ "description": "English: Reset to default settings..." }, "aboutRestoreDataConfirm": { - "message": "All your settings will be overwritten using data backed up on {{time}}, and uBlock₀ will restart.\n\nOverwrite all existing settings using backed up data?", + "message": "{{time}}මත උපස්ථ කළ දත්ත භාවිතයෙන් ඔබගේ සියලු සැකසුම් උඩින් ලියනු ලබන අතර, uBlock₀ නැවත ආරම්භ වේ.\n\nඋපස්ථ කළ දත්ත භාවිතයෙන් පවතින සියලුම සැකසුම් උඩින් ලියන්නද?", "description": "Message asking user to confirm restore" }, "aboutRestoreDataError": { - "message": "The data could not be read or is invalid", + "message": "දත්ත කියවිය නොහැකි විය නැතහොත් අවලංගුය.", "description": "Message to display when an error occurred during restore" }, "aboutResetDataConfirm": { - "message": "All your settings will be removed, and uBlock₀ will restart.\n\nReset uBlock₀ to factory settings?", + "message": "ඔබගේ සියලු සැකසුම් ඉවත් කරනු ලබන අතර, uBlock₀ නැවත ආරම්භ වේ.\n\nuBlock₀ කර්මාන්තශාලා සැකසුම් වෙත නැවත සකසන්නද?", "description": "Message asking user to confirm reset" }, "errorCantConnectTo": { @@ -1100,11 +1100,11 @@ "description": "English: Network error: {{msg}}" }, "subscriberConfirm": { - "message": "Add the following URL to your custom filter lists?\n\nTitle: \"{{title}}\"\nURL: {{url}}", + "message": "ඔබගේ අභිරුචි පෙරහන් ලැයිස්තුවලට පහත URL එක එක් කරන්නද?\n\nමාතෘකාව: \"{{title}}\"\nURL: {{url}}", "description": "No longer used" }, "subscribeButton": { - "message": "Subscribe", + "message": "දායක වන්න", "description": "For the button used to subscribe to a filter list" }, "elapsedOneMinuteAgo": { @@ -1136,7 +1136,7 @@ "description": "Firefox/Fennec-specific: Show Dashboard" }, "showNetworkLogButton": { - "message": "Show Logger", + "message": "ලඝුව පෙන්වන්න", "description": "Firefox/Fennec-specific: Show Logger" }, "fennecMenuItemBlockingOff": { @@ -1148,15 +1148,15 @@ "description": "Used as a title for the document-blocked page" }, "docblockedPrompt1": { - "message": "uBlock Origin has prevented the following page from loading:", + "message": "uBlock Origin විසින් පහත පිටුව පූරණය වීම වළක්වා ඇත:", "description": "Used in the strict-blocking page" }, "docblockedPrompt2": { - "message": "Because of the following filter:", + "message": "පහත පෙරහන නිසා:", "description": "Used in the strict-blocking page" }, "docblockedNoParamsPrompt": { - "message": "without parameters", + "message": "පරාමිතීන් නොමැතිව", "description": "label to be used for the parameter-less URL: https://cloud.githubusercontent.com/assets/585534/9832014/bfb1b8f0-593b-11e5-8a27-fba472a5529a.png" }, "docblockedFoundIn": { @@ -1172,11 +1172,11 @@ "description": "English: Close this window" }, "docblockedDontWarn": { - "message": "Don't warn me again about this site", + "message": "මෙම අඩවිය ගැන මට නැවත අනතුරු අඟවන්න එපා.", "description": "Label for checkbox in document-blocked page" }, "docblockedProceed": { - "message": "Disable strict blocking for {{hostname}}", + "message": "{{hostname}}සඳහා දැඩි අවහිර කිරීම අක්‍රීය කරන්න", "description": "English: Disable strict blocking for {{hostname}} ..." }, "docblockedDisableTemporary": { @@ -1188,13 +1188,29 @@ "description": "English: Permanently" }, "docblockedDisable": { - "message": "Proceed", + "message": "ඉදිරියට", "description": "Button text to navigate to the blocked page" }, "docblockedRedirectPrompt": { - "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", + "message": "අවහිර කළ පිටුව වෙනත් අඩවියකට හරවා යැවීමට අවශ්‍යයි. ඔබ ඉදිරියට යාමට තෝරා ගන්නේ නම්, ඔබ කෙලින්ම මෙහි සංචාලනය කරනු ඇත: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "මේඝ ආචයනයට නිර්යාත කරන්න", "description": "tooltip" @@ -1236,15 +1252,15 @@ "description": "" }, "contextMenuBlockElementInFrame": { - "message": "Block element in frame…", + "message": "රාමුවේ බ්ලොක් මූලද්‍රව්‍යය…", "description": "An entry in the browser's contextual menu" }, "contextMenuSubscribeToList": { - "message": "Subscribe to filter list…", + "message": "පෙරහන් ලැයිස්තුවට දායක වන්න…", "description": "An entry in the browser's contextual menu" }, "contextMenuTemporarilyAllowLargeMediaElements": { - "message": "Temporarily allow large media elements", + "message": "තාවකාලිකව විශාල මාධ්‍ය අංගවලට ඉඩ දෙන්න.", "description": "A context menu entry, present when large media elements have been blocked on the current site" }, "contextMenuViewSource": { @@ -1256,7 +1272,7 @@ "description": "Placeholder string for input field used to capture a keyboard shortcut" }, "genericMergeViewScrollLock": { - "message": "Toggle locked scrolling", + "message": "අගුළු දැමූ අනුචලනය ටොගල් කරන්න", "description": "Tooltip for the button used to lock scrolling between the views in the 'My rules' pane" }, "genericCopyToClipboard": { @@ -1268,15 +1284,15 @@ "description": "Label for buttons used to select all text in editor" }, "toggleCosmeticFiltering": { - "message": "Toggle cosmetic filtering", + "message": "රූපලාවන්‍ය පෙරහන ටොගල් කරන්න", "description": "Label for keyboard shortcut used to toggle cosmetic filtering" }, "toggleJavascript": { - "message": "Toggle JavaScript", + "message": "ජාවාස්ක්‍රිප්ට් ටොගල් කරන්න", "description": "Label for keyboard shortcut used to toggle no-scripting switch" }, "relaxBlockingMode": { - "message": "Relax blocking mode", + "message": "අවහිර කිරීමේ මාදිලිය ලිහිල් කරන්න", "description": "Label for keyboard shortcut used to relax blocking mode" }, "storageUsed": { @@ -1304,7 +1320,7 @@ "description": "Summary of number of errors as reported by the linter " }, "unprocessedRequestTooltip": { - "message": "Could not filter properly at browser launch. Reload the page to ensure proper filtering.", + "message": "බ්‍රව්සරය දියත් කිරීමේදී නිසි ලෙස පෙරීමට නොහැකි විය. නිසි පෙරහන සහතික කිරීම සඳහා පිටුව නැවත පූරණය කරන්න.", "description": "A warning which will appear in the popup panel if needed" }, "dummy": { diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/sk/messages.json ublock-origin-1.67.0+dfsg/src/_locales/sk/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/sk/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/sk/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -340,11 +340,11 @@ "description": "Section for controlling user interface appearance" }, "settingsThemeLabel": { - "message": "Téma", + "message": "Motív", "description": "Label for checkbox to enable a custom dark theme" }, "settingsThemeAccent0Label": { - "message": "Vlastná farba témy", + "message": "Vlastná farba motívu", "description": "Label for checkbox to pick an accent color" }, "settingsCloudStorageEnabledPrompt": { @@ -372,7 +372,7 @@ "description": "" }, "settingPerSiteSwitchGroupSynopsis": { - "message": "Tieto predvolené správania môžu byť prepísané u jednotlivých stránkach", + "message": "Tieto predvolené správania môžu byť prepísané na jednotlivých stránkach", "description": "" }, "settingsNoCosmeticFilteringPrompt": { @@ -1084,7 +1084,7 @@ "description": "English: Reset to default settings..." }, "aboutRestoreDataConfirm": { - "message": "Všetky vaše nastavenia budú prepísané pomocou dáta zálohovaných dňa {{time}} a uBlock sa reštartne.\n\nPrepísať všetky existujúce nastavenia pomocou zálohovaných dát?", + "message": "Všetky vaše nastavenia budú prepísané dátami zálohovanými {{time}} a uBlock sa reštartuje.\n\nPrepísať všetky existujúce nastavenia pomocou zálohovaných dát?", "description": "Message asking user to confirm restore" }, "aboutRestoreDataError": { @@ -1195,6 +1195,22 @@ "message": "Zablokovaná stránka chce presmerovať na inú stránku. Ak sa rozhodnete pokračovať, prejdete priamo na: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Dôvod:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Škodlivé", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Sledovač", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Pochybné", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exportovať do cloudového úložiska", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/sl/messages.json ublock-origin-1.67.0+dfsg/src/_locales/sl/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/sl/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/sl/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Izvozi v shrambe oblaka", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/so/messages.json ublock-origin-1.67.0+dfsg/src/_locales/so/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/so/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/so/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "{{value}} saac kahor", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/sq/messages.json ublock-origin-1.67.0+dfsg/src/_locales/sq/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/sq/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/sq/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -480,7 +480,7 @@ "description": "Filter lists section name" }, "3pGroupMalware": { - "message": "Domenet e rrezikshme, siguria", + "message": "Domenet e dëmshme, siguria", "description": "Filter lists section name" }, "3pGroupSocial": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Krijoj raport të ri", + "message": "Krijoj raport të ri në GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Gjej raporte të ngjashme", + "message": "Gjej raporte të ngjashme në GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Verifikoni a është raportuar më parë problemi që të mos i lodhni vullnetarët e tjerë me të njëjtat gjëra.", + "message": "Verifikoni a është raportuar edhe më parë që të mos i lodhni vullnetarët e tjerë me të njëjtat probleme. Shënim: kur klikoni butonin, origjina e faqes do të dërgohet në GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "Faqja e bllokuar do t'ju drejtojë në një uebsajt tjetër. Në rast se vijoni do të shkoni te: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Arsyeja:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Dëmtuese", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Gjurmues", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Joserioze", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Eksportoni në renë informatike", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/sr/messages.json ublock-origin-1.67.0+dfsg/src/_locales/sr/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/sr/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/sr/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -1195,6 +1195,22 @@ "message": "Блокирана страница жели да преусмери на други сајт. Ако одлучите да наставите, ићи ћете директно на: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Разлог:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Злонамерно", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Праћење", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Неугледан", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Извези у складиште у облаку", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/sv/messages.json ublock-origin-1.67.0+dfsg/src/_locales/sv/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/sv/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/sv/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Äntligen en effektiv blockerare. Skonsam mot både processor och minne.", + "message": "Äntligen en effektiv blockerare. Lätt för både processor och minne.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "dashboardName": { @@ -116,7 +116,7 @@ "description": "English: Click to open the dashboard" }, "popupTipZapper": { - "message": "Gå till elementzapperläge", + "message": "Gå in i elementzapperläge", "description": "Tooltip for the element-zapper icon in the popup panel" }, "popupTipPicker": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Skapa ny rapport", + "message": "Skapa ny rapport på GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Hitta liknande rapporter", + "message": "Hitta liknande rapporter på GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "För att undvika att belasta volontärer med dubbletter av rapporter, kontrollera att problemet inte redan har rapporterats.", + "message": "För att undvika att belasta volontärer med dubbletter av rapporter, kontrollera att problemet inte redan har rapporterats. Observera: om du klickar på knappen kommer sidans ursprung att skickas till GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "Den blockerade sidan vill omdirigera dig till en annan webbplats. Om du väljer att fortsätta skickas du direkt till: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Anledning:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Illvillig", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Spårare", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Vanhedrande", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exportera till molnlagring", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/sw/messages.json ublock-origin-1.67.0+dfsg/src/_locales/sw/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/sw/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/sw/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Hamisha hadi hifadhi ya wingu", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/ta/messages.json ublock-origin-1.67.0+dfsg/src/_locales/ta/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/ta/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/ta/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "மேகக்கணினி சேமிப்பகத்திற்கு ஏற்று", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/te/messages.json ublock-origin-1.67.0+dfsg/src/_locales/te/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/te/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/te/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "క్లౌడ్ లో పొందుపరచు", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/th/messages.json ublock-origin-1.67.0+dfsg/src/_locales/th/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/th/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/th/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -28,7 +28,7 @@ "description": "appears as tab name in dashboard" }, "3pPageName": { - "message": "ตัวกรองจากที่อื่น", + "message": "รายการตัวกรอง", "description": "appears as tab name in dashboard" }, "1pPageName": { @@ -36,19 +36,19 @@ "description": "appears as tab name in dashboard" }, "rulesPageName": { - "message": "กฎของฉัน", + "message": "เงื่อนไขของฉัน", "description": "appears as tab name in dashboard" }, "whitelistPageName": { - "message": "รายการยกเว้น", + "message": "เว็บไซต์ที่เชื่อถือได้", "description": "appears as tab name in dashboard" }, "shortcutsPageName": { - "message": "Shortcuts", + "message": "ทางลัด", "description": "appears as tab name in dashboard" }, "statsPageName": { - "message": "uBlock₀ — ประวัติ", + "message": "uBlock₀ — บันทึก", "description": "Title for the logger window" }, "aboutPageName": { @@ -56,11 +56,11 @@ "description": "appears as tab name in dashboard" }, "supportPageName": { - "message": "ช่วยเหลือ", + "message": "สนับสนุน", "description": "appears as tab name in dashboard" }, "assetViewerPageName": { - "message": "uBlock₀ — Asset viewer", + "message": "uBlock₀ — โปรแกรมดูสิ่งที่ถือครอง", "description": "Title for the asset viewer page" }, "advancedSettingsPageName": { @@ -68,11 +68,11 @@ "description": "Title for the advanced settings page" }, "popupPowerSwitchInfo": { - "message": "Click: เปิด/ปิดการทำงานของ uBlock₀ สำหรับเว็บไซต์นี้ \nCtrl+click: ปิดการทำงานของ uBlock₀ เฉพาะหน้าเว็บนี้", + "message": "คลิก: ปิด/เปิดการทำงานของ uBlock₀ สำหรับเว็บไซต์นี้ \nCtrl+คลิก: ปิดการทำงานของ uBlock₀ เฉพาะหน้าเว็บนี้", "description": "English: Click: disable/enable uBlock₀ for this site.\n\nCtrl+click: disable uBlock₀ only on this page." }, "popupPowerSwitchInfo1": { - "message": "Click to disable uBlock₀ for this site.\n\nCtrl+click to disable uBlock₀ only on this page.", + "message": "คลิกเพื่อปิดใช้งาน uBlock₀ สำหรับเว็บไซต์นี้\n\nCtrl+คลิกเพื่อปิดใช้งาน uBlock₀ เฉพาะในหน้านี้", "description": "Message to be read by screen readers" }, "popupPowerSwitchInfo2": { @@ -88,7 +88,7 @@ "description": "English: on this page" }, "popupBlockedStats": { - "message": "{{count}} or {{percent}}%", + "message": "{{count}} ({{percent}}%)", "description": "Example: 15 (13%)" }, "popupBlockedSinceInstallPrompt": { @@ -108,7 +108,7 @@ "description": "For the new mobile-friendly popup design" }, "popupDomainsConnected_v2": { - "message": "Domains connected", + "message": "โดเมนที่เชื่อมต่อ", "description": "For the new mobile-friendly popup design" }, "popupTipDashboard": { @@ -128,7 +128,7 @@ "description": "Tooltip used for the logger icon in the panel" }, "popupTipReport": { - "message": "Report an issue on this website", + "message": "แจ้งปัญหาการใช้งานเว็บไซต์", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipNoPopups": { @@ -156,7 +156,7 @@ "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoCosmeticFiltering": { - "message": "Toggle cosmetic filtering for this site", + "message": "สลับการกรององค์ประกอบตกแต่งสำหรับเว็บไซต์นี้", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoCosmeticFiltering1": { @@ -164,11 +164,11 @@ "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoCosmeticFiltering2": { - "message": "Click to enable cosmetic filtering on this site", + "message": "คลิกเพื่อเปิดใช้งานการกรององค์ประกอบตกแต่งในเว็บไซต์นี้", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoRemoteFonts": { - "message": "Toggle the blocking of remote fonts for this site", + "message": "สลับเป็นฟอนต์เครื่องที่บล็อกสำหรับเว็บนี้", "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoRemoteFonts1": { @@ -384,7 +384,7 @@ "description": "" }, "settingsNoRemoteFontsPrompt": { - "message": "Block remote fonts", + "message": "ฟอนต์เครื่องที่บล็อก", "description": "" }, "settingsNoScriptingPrompt": { @@ -396,7 +396,7 @@ "description": "background information: https://github.com/gorhill/uBlock/issues/3150" }, "settingsUncloakCnamePrompt": { - "message": "Uncloak canonical names", + "message": "เปิดเผยชื่อตามหลักเกณฑ์", "description": "background information: https://github.com/uBlockOrigin/uBlock-issues/issues/1513" }, "settingsAdvanced": { @@ -420,11 +420,11 @@ "description": "English: Last backup:" }, "3pListsOfBlockedHostsPrompt": { - "message": "{{netFilterCount}} network filters + {{cosmeticFilterCount}} cosmetic filters from:", + "message": "{{netFilterCount}} ตัวกรองเครือข่าย + {{cosmeticFilterCount}} ตกแต่งตัวกรองจาก:", "description": "Appears at the top of the _3rd-party filters_ pane" }, "3pListsOfBlockedHostsPerListStats": { - "message": "{{used}} used out of {{total}}", + "message": "{{used}} ใช้ไปแล้วจาก {{total}}", "description": "Appears aside each filter list in the _3rd-party filters_ pane" }, "3pAutoUpdatePrompt1": { @@ -452,7 +452,7 @@ "description": "This will cause uBO to ignore all generic cosmetic filters." }, "3pIgnoreGenericCosmeticFiltersInfo": { - "message": "Generic cosmetic filters are those cosmetic filters which are meant to apply on all web sites. Enabling this option will eliminate the memory and CPU overhead added to web pages as a result of handling generic cosmetic filters.\n\nIt is recommended to enable this option on less powerful devices.", + "message": "ตัวกรองส่วนแสดงผลทั่วไปคือตัวกรองที่สร้างขึ้นเพื่อใช้กับทุกเว็บไซต์ การเปิดใช้งานตัวเลือกนี้จะช่วยลดการใช้หน่วยความจำและ CPU ที่เพิ่มขึ้นบนหน้าเว็บ ซึ่งเกิดจากการทำงานของตัวกรองเหล่านี้\n\nแนะนำให้เปิดใช้งานตัวเลือกนี้บนอุปกรณ์ที่มีประสิทธิภาพต่ำ", "description": "Describes the purpose of the 'Ignore generic cosmetic filters' feature." }, "3pSuspendUntilListsAreLoaded": { @@ -484,11 +484,11 @@ "description": "Filter lists section name" }, "3pGroupSocial": { - "message": "Social widgets", + "message": "วิดเจ็ตโซเชียล", "description": "Filter lists section name" }, "3pGroupCookies": { - "message": "Cookie notices", + "message": "คำประกาศการใช้คุ้กกี้", "description": "Filter lists section name" }, "3pGroupAnnoyances": { @@ -532,27 +532,27 @@ "description": "used as a tooltip for the spinner icon beside a list" }, "3pNetworkError": { - "message": "A network error prevented the resource from being updated.", + "message": "ความผิดพลาดของเครือข่ายขวางกั้นการอัปเดต", "description": "used as a tooltip for error icon beside a list" }, "1pTrustWarning": { - "message": "Do not add filters from untrusted sources.", + "message": "ไม่อนุญาตให้เพิ่มตัวกรองจากแหล่งที่มาที่ไม่น่าเชื่อถือ", "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { - "message": "Enable my custom filters", + "message": "เปิดใช้งานการปรับแต่งตัวกรองของฉัน", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { - "message": "Allow custom filters requiring trust", + "message": "อนุญาตการปรับแต่งตัวกรองที่ต้องมีความน่าเชื่อถือ", "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { - "message": "Import and append…", + "message": "นำเข้าและเพิ่มต่อท้าย…", "description": "Button in the 'My filters' pane" }, "1pExport": { - "message": "Export…", + "message": "ส่งออก", "description": "Button in the 'My filters' pane" }, "1pExportFilename": { @@ -560,7 +560,7 @@ "description": "English: my-ublock-static-filters_{{datetime}}.txt" }, "1pApplyChanges": { - "message": "Apply changes", + "message": "นำไปใช้", "description": "English: Apply changes" }, "rulesPermanentHeader": { @@ -576,7 +576,7 @@ "description": "This will remove all temporary rules" }, "rulesCommit": { - "message": "Commit", + "message": "ยืนยัน", "description": "This will persist temporary rules" }, "rulesEdit": { @@ -604,11 +604,11 @@ "description": "default file name to use" }, "rulesHint": { - "message": "List of your dynamic filtering rules.", + "message": "รายการเงื่อนไขตัวกรองแบบไดนามิกของคุณ", "description": "English: List of your dynamic filtering rules." }, "rulesFormatHint": { - "message": "Rule syntax: source destination type action (full documentation).", + "message": "ข้อกำหนดเงื่อนไข: การดำเนินการประเภทแหล่งปลายทาง (เอกสารฉบับเต็ม)", "description": "English: dynamic rule syntax and full documentation." }, "rulesSort": { @@ -668,7 +668,7 @@ "description": "Appears in the logger's tab selector" }, "logBehindTheScene": { - "message": "Tabless", + "message": "ตาราง", "description": "Pretty name for behind-the-scene network requests" }, "loggerCurrentTab": { @@ -680,19 +680,19 @@ "description": "Tooltip for the reload button in the logger page" }, "loggerDomInspectorTip": { - "message": "Toggle the DOM inspector", + "message": "สลับตัวตรวจสอบ DOM", "description": "Tooltip for the DOM inspector button in the logger page" }, "loggerPopupPanelTip": { - "message": "Toggle the popup panel", + "message": "สลับแผงป๊อปอัป", "description": "Tooltip for the popup panel button in the logger page" }, "loggerInfoTip": { - "message": "uBlock Origin wiki: The logger", + "message": "uBlock Origin wiki: ตัวลงบันทึก", "description": "Tooltip for the top-right info label in the logger page" }, "loggerClearTip": { - "message": "Clear logger", + "message": "ล้างบันทึก", "description": "Tooltip for the eraser in the logger page; used to blank the content of the logger" }, "loggerPauseTip": { @@ -700,23 +700,23 @@ "description": "Tooltip for the pause button in the logger page" }, "loggerUnpauseTip": { - "message": "Unpause logger", + "message": "ยกเลิกการหยุดบันทึกชั่วคราว", "description": "Tooltip for the play button in the logger page" }, "loggerRowFiltererButtonTip": { - "message": "Toggle logger filtering", + "message": "สลับตัวกรองบันทึก", "description": "Tooltip for the row filterer button in the logger page" }, "logFilterPrompt": { - "message": "filter logger content", + "message": "ตัวกรองเนื้อหาบันทึก", "description": "Placeholder string for logger output filtering input field" }, "loggerRowFiltererBuiltinTip": { - "message": "Logger filtering options", + "message": "ตัวเลือกตัวกรองบันทึก", "description": "Tooltip for the button to bring up logger output filtering options" }, "loggerRowFiltererBuiltinNot": { - "message": "Not", + "message": "ไม่", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltinEventful": { @@ -724,19 +724,19 @@ "description": "A keyword in the built-in row filtering expression: all items corresponding to uBO doing something (blocked, allowed, redirected, etc.)" }, "loggerRowFiltererBuiltinBlocked": { - "message": "blocked", + "message": "บล๊อกอยู่", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltinAllowed": { - "message": "allowed", + "message": "อนุญาต", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltinModified": { - "message": "modified", + "message": "แก้ไขแล้ว", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltin1p": { - "message": "1st-party", + "message": "ฝ่ายที่ 1", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltin3p": { @@ -760,19 +760,19 @@ "description": "Label to identify a rule field" }, "loggerEntryDetailsContext": { - "message": "Context", + "message": "บริบท", "description": "Label to identify a context field (typically a hostname)" }, "loggerEntryDetailsRootContext": { - "message": "Root context", + "message": "ปฐมบท", "description": "Label to identify a root context field (typically a hostname)" }, "loggerEntryDetailsPartyness": { - "message": "Partyness", + "message": "การรวมกลุ่ม", "description": "Label to identify a field providing partyness information" }, "loggerEntryDetailsType": { - "message": "Type", + "message": "ประเภท", "description": "Label to identify the type of an entry" }, "loggerEntryDetailsURL": { @@ -780,11 +780,11 @@ "description": "Label to identify the URL of an entry" }, "loggerURLFilteringHeader": { - "message": "URL rule", + "message": "เงื่อนไข URL", "description": "Small header to identify the dynamic URL filtering section" }, "loggerURLFilteringContextLabel": { - "message": "Context:", + "message": "บริบท:", "description": "Label for the context selector" }, "loggerURLFilteringTypeLabel": { @@ -792,11 +792,11 @@ "description": "Label for the type selector" }, "loggerStaticFilteringHeader": { - "message": "Static filter", + "message": "ตัวกรองแบบคงที่", "description": "Small header to identify the static filtering section" }, "loggerStaticFilteringSentence": { - "message": "{{action}} network requests of {{type}} {{br}}which URL address matches {{url}} {{br}}and which originates {{origin}},{{br}}{{importance}} there is a matching exception filter.", + "message": "{{action}} การร้องขอเครือข่ายของ {{type}} {{br}}ซึ่ง URL ตรงกันกับ {{url}} {{br}}และมีต้นทางที่ {{origin}},{{br}}{{importance}} มีตัวกรองที่ยกเว้นตรงกัน", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartBlock": { @@ -808,23 +808,23 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartType": { - "message": "type “{{type}}”", + "message": "ประเภท “{{type}}”", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartAnyType": { - "message": "any type", + "message": "ประเภทใดก็ได้", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartOrigin": { - "message": "from “{{origin}}”", + "message": "จาก “{{origin}}”", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartAnyOrigin": { - "message": "from anywhere", + "message": "จากที่ใดก็ได้", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartNotImportant": { - "message": "except when", + "message": "ยกเว้นเมื่อ", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartImportant": { @@ -832,31 +832,31 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringFinderSentence1": { - "message": "Static filter {{filter}} found in:", + "message": "ตัวกรองแบบคงที่ {{filter}} พบใน:", "description": "Below this sentence, the filter list(s) in which the filter was found" }, "loggerStaticFilteringFinderSentence2": { - "message": "Static filter could not be found in any of the currently enabled filter lists", + "message": "ตัวกรองแบบคงที่ไม่พบในรายการตัวกรองที่เปิดอยู่", "description": "Message to show when a filter cannot be found in any filter lists" }, "loggerSettingDiscardPrompt": { - "message": "Logger entries which do not fulfill all three conditions below will be automatically discarded:", + "message": "รายการบันทึกที่ไม่ครบถ้วนทั้ง 3 เงื่อนไขตามด้านล่างจะถูกละทิ้งโดยอัตโนมัติ", "description": "Logger setting: A sentence to describe the purpose of the settings below" }, "loggerSettingPerEntryMaxAge": { - "message": "Preserve entries from the last {{input}} minutes", + "message": "สงวนรายการ {{input}} นาที", "description": "A logger setting" }, "loggerSettingPerTabMaxLoads": { - "message": "Preserve at most {{input}} page loads per tab", + "message": "สงวนจำนวนมากที่สุด {{input}} หน้าโหลดต่อแท็บ", "description": "A logger setting" }, "loggerSettingPerTabMaxEntries": { - "message": "Preserve at most {{input}} entries per tab", + "message": "สงวนจำนวนมากที่สุด {{input}} รายการต่อแท็บ", "description": "A logger setting" }, "loggerSettingPerEntryLineCount": { - "message": "Use {{input}} lines per entry in vertically expanded mode", + "message": "ใช้ {{input}} บรรทัดต่อรายการในโหมดการขยายแนวตั้ง", "description": "A logger setting" }, "loggerSettingHideColumnsPrompt": { @@ -872,11 +872,11 @@ "description": "A label for the filter or rule column" }, "loggerSettingHideColumnContext": { - "message": "{{input}} Context", + "message": "{{input}} บริบท", "description": "A label for the context column" }, "loggerSettingHideColumnPartyness": { - "message": "{{input}} Partyness", + "message": "{{input}} การจัดกลุ่ม", "description": "A label for the partyness column" }, "loggerExportFormatList": { @@ -888,11 +888,11 @@ "description": "Label for radio-button to pick export format" }, "loggerExportEncodePlain": { - "message": "Plain", + "message": "ธรรมดา", "description": "Label for radio-button to pick export text format" }, "loggerExportEncodeMarkdown": { - "message": "Markdown", + "message": "ทำเครื่องหมายลง", "description": "Label for radio-button to pick export text format" }, "supportOpenButton": { @@ -904,7 +904,7 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "ค้นหารายงานคล้ายกันบน GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -912,31 +912,31 @@ "description": "Header of 'Documentation' section in Support pane" }, "supportS1P1": { - "message": "Read the documentation at uBlock/wiki to learn about all of uBlock Origin's features.", + "message": "อ่านเอกสารข้อมูลที่ uBlock/wiki เพื่อเรียนรู้ฟีเจอร์ทั้งหมดของ uBlock Origin", "description": "First paragraph of 'Documentation' section in Support pane" }, "supportS2H": { - "message": "Questions and support", + "message": "คำถามและการสนับสนุน", "description": "Header of 'Questions and support' section in Support pane" }, "supportS2P1": { - "message": "Answers to questions and other kinds of help support is provided on the subreddit /r/uBlockOrigin.", + "message": "การตอบคำถามและการสนับสนุนอื่น ๆ ที่เตรียมไว้ให้บน subreddit /r/uBlockOrigin", "description": "First paragraph of 'Questions and support' section in Support pane" }, "supportS3H": { - "message": "Filter issues/website is broken", + "message": "คัดกรองปัญหา/เว็บไซต์ที่ไม่สมบูรณ์", "description": "Header of 'Filter issues' section in Support pane" }, "supportS3P1": { - "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", + "message": "รายงานปัญหาการกรองด้วยเว็บไซต์เฉพาะที่ uBlockOrigin/uAssets ตัวติดตามปัญหา. ต้องใช้บัญชี GitHub", "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { - "message": "Important: Avoid using other similarly-purposed blockers along with uBlock Origin, as this may cause filter issues on specific websites.", + "message": "สำคัญ: หลีกเลี่ยงการใช้ตัวบล๊อกอื่น ๆ ร่วมกันกับ uBlock Origin ซึ่งอาจทำให้เกิดปัญหาในการกรองของหน้าเว็บไซต์ที่ต้องการ", "description": "Second paragraph of 'Filter issues' section in Support pane" }, "supportS3P3": { - "message": "Tips: Be sure your filter lists are up to date. The logger is the primary tool to diagnose filter-related issues.", + "message": "เคล็ดลับ: ให้แน่ใจว่ารายการตัวกรองของคุณได้รับการอัปเดตแล้ว ตัวบันทึก เป็นเครื่องมือหลักในการวินิจฉัยปัญหาที่เกี่ยวเนื่อง", "description": "Third paragraph of 'Filter issues' section in Support pane" }, "supportS4H": { @@ -944,43 +944,43 @@ "description": "Header of 'Bug report' section in Support pane" }, "supportS4P1": { - "message": "Report issues with uBlock Origin itself to the uBlockOrigin/uBlock-issue issue tracker. Requires a GitHub account.", + "message": "รายงานปัญหาด้วย uBlock Origin เอง uBlockOrigin/uBlock-issue ปัญหาตัวติดตาม. ต้องใช้บัญชี GitHub", "description": "First paragraph of 'Bug report' section in Support pane" }, "supportS5H": { - "message": "Troubleshooting Information", + "message": "ข้อมูลการแก้ไขปัญหา", "description": "Header of 'Troubleshooting Information' section in Support pane" }, "supportS5P1": { - "message": "Below is technical information that might be useful when volunteers are trying to help you solve a problem.", + "message": "ด้านล่างนี้เป็นข้อมูลทางเทคนิคซึ่งอาจเป็นประโยชน์ในกรณีที่อาสาสมัครพยายามให้การช่วยเหลือในการแก้ไขปัญหาให้คุณ", "description": "First paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS5P2": { - "message": "Important: Potentially private or sensitive information is redacted by default. Redacted information may make it more difficult to solve a problem.", + "message": "สำคัญ: ข้อมูลที่อาจเป็นความลับหรือละเอียดอ่อนจะถูกแก้ไขตามค่าเริ่มต้น ข้อมูลที่แก้ไขอาจะทำให้การแก้ไขปัญหายากขึ้น", "description": "Second paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS6H": { - "message": "Report a filter issue", + "message": "รายงานปัญหาตัวกรอง", "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "เพื่อเป็นการลดภาระอาสาสมัครจากการรายงานซ้ำซ้อน โปรดตรวจสอบก่อนว่าปัญหาดังกล่าวได้รับการรายงานไปแล้วหรือยัง หมายเหตุ: คลิกที่ปุ่มจะเป็นการส่งต้นทางของหน้าเว็บไปยัง GitHub", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { - "message": "Filter lists are updated daily. Be sure your issue has not already been addressed in the most recent filter lists.", + "message": "มีการอัปเดตรายการตัวกรองประจำวัน ให้แน่ใจว่าปัญหาของคุณยังไม่ได้ระบุไว้ในรายการตัวกรองล่าสุด", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S2": { - "message": "Verify that the issue still exists after reloading the problematic webpage.", + "message": "ตรวจสอบว่าปัญหายังคงอยู่หลังจากมีการโหลดหน้าเว็บเพจที่มีปัญหาซ้ำแล้ว", "description": "A paragraph in the filter issue reporter section" }, "supportS6URL": { - "message": "Address of the web page:", + "message": "ที่อยู่ของเว็บเพจ:", "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "The web page…", + "message": "เว็บเพจ…", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { @@ -988,35 +988,35 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { - "message": "Shows ads or ad leftovers", + "message": "แสดงโฆษณาหรือสิ่งที่ตกค้างอยู่", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "Has overlays or other nuisances", + "message": "มีโอเวอร์เลย์หรือสิ่งอื่น ๆ ที่รบกวน", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { - "message": "Detects uBlock Origin", + "message": "ตรวจหา uBlock Origin", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { - "message": "Has privacy-related issues", + "message": "มีปัญหาที่เกี่ยวเนื่องกับความเป็นส่วนตัว", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "Malfunctions when uBlock Origin is enabled", + "message": "ความผิดปกติเมื่อเปิดใช้งาน uBlock Origin", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { - "message": "Opens unwanted tabs or windows", + "message": "เปิดแท็บหรือหน้าต่างที่ไม่ต้องการ", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { - "message": "Leads to badware, phishing", + "message": "นำไปสู่แบดแวร์ ฟิชชิ่ง", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { - "message": "Label the web page as “NSFW” (“Not Safe For Work”)", + "message": "ติดป้ายเว็บเพจว่าเป็น “NSFW” (“ไม่ปลอดภัยกับงาน (Not Safe For Work)”)", "description": "A checkbox to use for NSFW sites" }, "supportRedact": { @@ -1032,11 +1032,11 @@ "description": "Link to privacy policy on GitHub (English)" }, "aboutChangelog": { - "message": "Changelog", + "message": "บันทึกการเปลี่ยนแปลง", "description": "" }, "aboutCode": { - "message": "Source code (GPLv3)", + "message": "ซอร์สโค้ด (GPLv3)", "description": "English: Source code (GPLv3)" }, "aboutContributors": { @@ -1044,7 +1044,7 @@ "description": "English: Contributors" }, "aboutSourceCode": { - "message": "Source code", + "message": "ซอร์สโค้ด", "description": "Link text to source code repo" }, "aboutTranslations": { @@ -1052,7 +1052,7 @@ "description": "Link text to translations repo" }, "aboutFilterLists": { - "message": "Filter lists", + "message": "รายการตัวกรอง", "description": "Link text to uBO's own filter lists repo" }, "aboutDependencies": { @@ -1060,7 +1060,7 @@ "description": "Shown in the About pane" }, "aboutCDNs": { - "message": "uBO's own filter lists are freely hosted on the following CDNs:", + "message": "uBO's ถือครองรายการตัวกรองที่เก็บไว้ที่ CDNs:", "description": "Shown in the About pane" }, "aboutCDNsInfo": { @@ -1068,7 +1068,7 @@ "description": "Shown in the About pane" }, "aboutBackupDataButton": { - "message": "Back up to file…", + "message": "แบ็กอัพไปยังไฟล์…", "description": "Text for button to create a backup of all settings" }, "aboutBackupFilename": { @@ -1076,27 +1076,27 @@ "description": "English: my-ublock-backup_{{datetime}}.txt" }, "aboutRestoreDataButton": { - "message": "Restore from file…", + "message": "คืนค่าจากไฟล์…", "description": "English: Restore from file..." }, "aboutResetDataButton": { - "message": "Reset to default settings…", + "message": "ปรับเป็นการตั้งค่าเริ่มต้น", "description": "English: Reset to default settings..." }, "aboutRestoreDataConfirm": { - "message": "All your settings will be overwritten using data backed up on {{time}}, and uBlock₀ will restart.\n\nOverwrite all existing settings using backed up data?", + "message": "การตั้งค่าทั้งหมดของคุณจะถูกเขียนทับโดยใช้ข้อมูลที่แบ็กอัพไว้บน {{time}} และ uBlock₀ จะรีสตาร์ท\n\nเขียนทับการตั้งค่าทั้งหมดด้วยข้อมูลที่แบ็กอัพหรือไม่?", "description": "Message asking user to confirm restore" }, "aboutRestoreDataError": { - "message": "The data could not be read or is invalid", + "message": "ไม่สามารถอ่านข้อมูลได้หรือข้อมูลไม่ถูกต้อง", "description": "Message to display when an error occurred during restore" }, "aboutResetDataConfirm": { - "message": "All your settings will be removed, and uBlock₀ will restart.\n\nReset uBlock₀ to factory settings?", + "message": "การตั้งค่าทั้งหมดของคุณจะถูกลบทิ้ง และ uBlock₀ จะรีสตาร์ท\n\nรีเซ็ต uBlock₀ เป็นค่าเริ่มต้นโรงงาน?", "description": "Message asking user to confirm reset" }, "errorCantConnectTo": { - "message": "Network error: {{msg}}", + "message": "เครือข่ายผิดพลาด: {{msg}}", "description": "English: Network error: {{msg}}" }, "subscriberConfirm": { @@ -1132,11 +1132,11 @@ "description": "English: {{value}} days ago" }, "showDashboardButton": { - "message": "Show Dashboard", + "message": "แสดงแดชบอร์ด", "description": "Firefox/Fennec-specific: Show Dashboard" }, "showNetworkLogButton": { - "message": "Show Logger", + "message": "แสดงบันทึก", "description": "Firefox/Fennec-specific: Show Logger" }, "fennecMenuItemBlockingOff": { @@ -1156,7 +1156,7 @@ "description": "Used in the strict-blocking page" }, "docblockedNoParamsPrompt": { - "message": "without parameters", + "message": "ไม่ระบุพารามิเตอร์", "description": "label to be used for the parameter-less URL: https://cloud.githubusercontent.com/assets/585534/9832014/bfb1b8f0-593b-11e5-8a27-fba472a5529a.png" }, "docblockedFoundIn": { @@ -1172,7 +1172,7 @@ "description": "English: Close this window" }, "docblockedDontWarn": { - "message": "Don't warn me again about this site", + "message": "ไม่ต้องแจ้งเตือนอีกเกี่ยวกับเว็บไซต์นี้", "description": "Label for checkbox in document-blocked page" }, "docblockedProceed": { @@ -1192,19 +1192,35 @@ "description": "Button text to navigate to the blocked page" }, "docblockedRedirectPrompt": { - "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", + "message": "เว็บเพจที่บล๊อกต้องการเด้งไปเว็บไซต์อื่น หากคุณต้องการดำเนินการต่อ คุณจะถูกนำทางโดยตรงไปที่: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "สาเหตุ", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "มัลแวร์", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "ตัวติดตาม", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "น่าสงสัย", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { - "message": "Export to cloud storage", + "message": "ส่งออกไปที่เก็บบนคลาวด์", "description": "tooltip" }, "cloudPull": { - "message": "Import from cloud storage", + "message": "นำเข้าจากที่เก็บบนคลาวด์", "description": "tooltip" }, "cloudPullAndMerge": { - "message": "Import from cloud storage and merge with current settings", + "message": "นำเข้าจากที่เก็บบนคลาวด์และผสานเข้ากับการตั้งค่าปัจจุบัน", "description": "tooltip" }, "cloudNoData": { @@ -1220,15 +1236,15 @@ "description": "A warning to users at the top of 'Advanced settings' page" }, "genericSubmit": { - "message": "Submit", + "message": "ยืนยัน", "description": "for generic 'Submit' buttons" }, "genericApplyChanges": { - "message": "Apply changes", + "message": "ใช้การเปลี่ยนแปลง", "description": "for generic 'Apply changes' buttons" }, "genericRevert": { - "message": "Revert", + "message": "คืนค่ากลับ", "description": "for generic 'Revert' buttons" }, "genericBytes": { @@ -1236,7 +1252,7 @@ "description": "" }, "contextMenuBlockElementInFrame": { - "message": "Block element in frame…", + "message": "บล๊อกองค์ประกอบในเฟรม…", "description": "An entry in the browser's contextual menu" }, "contextMenuSubscribeToList": { @@ -1252,15 +1268,15 @@ "description": "A context menu entry, to view the source code of the target resource" }, "shortcutCapturePlaceholder": { - "message": "Type a shortcut", + "message": "พิมพ์ทางลัด", "description": "Placeholder string for input field used to capture a keyboard shortcut" }, "genericMergeViewScrollLock": { - "message": "Toggle locked scrolling", + "message": "สลับการล็อกการเลื่อน", "description": "Tooltip for the button used to lock scrolling between the views in the 'My rules' pane" }, "genericCopyToClipboard": { - "message": "Copy to clipboard", + "message": "คัดลอกไปยังคลิปบอร์ด", "description": "Label for buttons used to copy something to the clipboard" }, "genericSelectAll": { @@ -1268,15 +1284,15 @@ "description": "Label for buttons used to select all text in editor" }, "toggleCosmeticFiltering": { - "message": "Toggle cosmetic filtering", + "message": "สลับตัวกรองการตกแต่ง", "description": "Label for keyboard shortcut used to toggle cosmetic filtering" }, "toggleJavascript": { - "message": "Toggle JavaScript", + "message": "สลับ JavaScript", "description": "Label for keyboard shortcut used to toggle no-scripting switch" }, "relaxBlockingMode": { - "message": "Relax blocking mode", + "message": "ผ่อนปรนโหมดการบล๊อก", "description": "Label for keyboard shortcut used to relax blocking mode" }, "storageUsed": { @@ -1300,11 +1316,11 @@ "description": "Message used in frame placeholders" }, "linterMainReport": { - "message": "Errors: {{count}}", + "message": "ข้อผิดพลาด: {{count}}", "description": "Summary of number of errors as reported by the linter " }, "unprocessedRequestTooltip": { - "message": "Could not filter properly at browser launch. Reload the page to ensure proper filtering.", + "message": "ไม่สามารถกรองได้สมบูรณ์เมื่อตอนเริ่มเบราว์เซอร์ โหลดหน้าเว็บใหม่เพื่อให้การกรองสมบูรณ์", "description": "A warning which will appear in the popup panel if needed" }, "dummy": { diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/tr/messages.json ublock-origin-1.67.0+dfsg/src/_locales/tr/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/tr/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/tr/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -632,7 +632,7 @@ "description": "A concise description of the 'Trusted sites' pane." }, "whitelistImport": { - "message": "İçe aktar ve ekle", + "message": "İçe aktar ve ekle…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Yeni rapor oluştur", + "message": "GitHub üzerinde yeni rapor oluştur", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Benzer raporları bul", + "message": "GitHub'da benzer raporları bul", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Gönüllülere aynı raporlarla sıkıntı vermemek için, lütfen sorunun daha önce bildirilmediğinden emin olun.", + "message": "Gönüllüleri yinelenen bildirimlerle meşgul etmemek için lütfen sorunun daha önce bildirilip bildirilmediğini kontrol edin.\nNot: Butona tıklamak, sayfanın kaynağının GitHub'a gönderilmesine neden olacaktır.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "Engellenen sayfa sizi başka bir siteye yönlendirmek istiyor. Devam etmek isterseniz doğrudan şuraya yönlendirileceksiniz: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Sebep:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Kötü niyetli", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "İzleyici", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Güvenilmez", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Bulut depolamaya aktar", "description": "tooltip" @@ -1272,7 +1288,7 @@ "description": "Label for keyboard shortcut used to toggle cosmetic filtering" }, "toggleJavascript": { - "message": "JavaScript'i Aç/Kapa", + "message": "JavaScript'i Aç/Kapat", "description": "Label for keyboard shortcut used to toggle no-scripting switch" }, "relaxBlockingMode": { diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/uk/messages.json ublock-origin-1.67.0+dfsg/src/_locales/uk/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/uk/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/uk/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -1195,6 +1195,22 @@ "message": "Заблокована сторінка хоче переадресувати на інший сайт. Якщо ви вирішите продовжити, ви перейдете безпосередньо на: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Причина:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Зловмисні", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Трекер", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Сумнівний вміст", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Експортувати до хмарного сховища", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/ur/messages.json ublock-origin-1.67.0+dfsg/src/_locales/ur/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/ur/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/ur/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1195,6 +1195,22 @@ "message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "کلاؤڈ سٹوریج میں برآمد کریں", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/vi/messages.json ublock-origin-1.67.0+dfsg/src/_locales/vi/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/vi/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/vi/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -312,7 +312,7 @@ "description": "English: Click, Ctrl-click" }, "pickerContextMenuEntry": { - "message": "Chặn phần tử...", + "message": "Chặn phần tử…", "description": "An entry in the browser's contextual menu" }, "settingsCollapseBlockedPrompt": { @@ -536,7 +536,7 @@ "description": "used as a tooltip for error icon beside a list" }, "1pTrustWarning": { - "message": "Không thêm các bộ lọc từ các nguồn không đáng tin cậy. ", + "message": "Không thêm các bộ lọc từ các nguồn không đáng tin cậy.", "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { @@ -548,11 +548,11 @@ "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { - "message": "Nhập và thêm vào", + "message": "Nhập và thêm vào…", "description": "Button in the 'My filters' pane" }, "1pExport": { - "message": "Xuất", + "message": "Xuất…", "description": "Button in the 'My filters' pane" }, "1pExportFilename": { @@ -596,7 +596,7 @@ "description": "" }, "rulesExport": { - "message": "Xuất ra tập tin", + "message": "Xuất ra tập tin…", "description": "Button in the 'My rules' pane" }, "rulesDefaultFileName": { @@ -632,11 +632,11 @@ "description": "A concise description of the 'Trusted sites' pane." }, "whitelistImport": { - "message": "Nhập và thêm vào", + "message": "Nhập và thêm vào…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { - "message": "Xuất", + "message": "Xuất…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExportFilename": { @@ -944,7 +944,7 @@ "description": "Header of 'Bug report' section in Support pane" }, "supportS4P1": { - "message": "Báo cáo lỗi cho uBlock Origin cho uBlockOrigin/uBlock-issue issue tracker. Cần tài khoản GitHub ", + "message": "Báo cáo lỗi cho uBlock Origin cho uBlockOrigin/uBlock-issue issue tracker. Cần tài khoản GitHub", "description": "First paragraph of 'Bug report' section in Support pane" }, "supportS5H": { @@ -980,7 +980,7 @@ "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "Trang web...", + "message": "Trang web…", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { @@ -1016,7 +1016,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { - "message": "Đánh dấu \"NFSW\" - Not Safe For Work cho trang web. Tìm hiểu về \"Not Safe For Work\"", + "message": "Đánh dấu \"NFSW\" - Not Safe For Work cho trang web.( Tìm hiểu về \"Not Safe For Work\")", "description": "A checkbox to use for NSFW sites" }, "supportRedact": { @@ -1068,7 +1068,7 @@ "description": "Shown in the About pane" }, "aboutBackupDataButton": { - "message": "Sao lưu vào tập tin...", + "message": "Sao lưu vào tập tin…", "description": "Text for button to create a backup of all settings" }, "aboutBackupFilename": { @@ -1076,11 +1076,11 @@ "description": "English: my-ublock-backup_{{datetime}}.txt" }, "aboutRestoreDataButton": { - "message": "Khôi phục từ tập tin...", + "message": "Khôi phục từ tập tin…", "description": "English: Restore from file..." }, "aboutResetDataButton": { - "message": "Đặt lại cấu hình mặc định...", + "message": "Đặt lại cấu hình mặc định…", "description": "English: Reset to default settings..." }, "aboutRestoreDataConfirm": { @@ -1195,6 +1195,22 @@ "message": "Trang đã chặn muốn chuyển hướng sang trang khác. Nếu đồng ý, bạn sẽ được chuyển hướng sang {{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "Lý do:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Độc hại", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Bộ theo dõi", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Không đáng tin cậy", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Xuất ra lưu trữ trực tuyến", "description": "tooltip" @@ -1236,11 +1252,11 @@ "description": "" }, "contextMenuBlockElementInFrame": { - "message": "Chặn phần tử trong khung ...", + "message": "Chặn phần tử trong khung…", "description": "An entry in the browser's contextual menu" }, "contextMenuSubscribeToList": { - "message": "Đăng ký danh sách bộ lọc ...", + "message": "Đăng ký danh sách bộ lọc…", "description": "An entry in the browser's contextual menu" }, "contextMenuTemporarilyAllowLargeMediaElements": { @@ -1248,7 +1264,7 @@ "description": "A context menu entry, present when large media elements have been blocked on the current site" }, "contextMenuViewSource": { - "message": "Xem mã nguồn...", + "message": "Xem mã nguồn…", "description": "A context menu entry, to view the source code of the target resource" }, "shortcutCapturePlaceholder": { diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/zh_CN/messages.json ublock-origin-1.67.0+dfsg/src/_locales/zh_CN/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/zh_CN/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/zh_CN/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -908,7 +908,7 @@ "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { - "message": "使用说明", + "message": "文档", "description": "Header of 'Documentation' section in Support pane" }, "supportS1P1": { @@ -1032,7 +1032,7 @@ "description": "Link to privacy policy on GitHub (English)" }, "aboutChangelog": { - "message": "变更日志", + "message": "更新日志", "description": "" }, "aboutCode": { @@ -1195,6 +1195,22 @@ "message": "被屏蔽的网页想重定向到另一个网站。如果您选择继续,将直接导航到:{{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "原因:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "恶意网站", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "跟踪器", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "不受信任", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "导出到云端储存", "description": "tooltip" diff -Nru ublock-origin-1.62.0+dfsg/src/_locales/zh_TW/messages.json ublock-origin-1.67.0+dfsg/src/_locales/zh_TW/messages.json --- ublock-origin-1.62.0+dfsg/src/_locales/zh_TW/messages.json 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/_locales/zh_TW/messages.json 2025-10-25 19:32:51.000000000 +0000 @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "終於,有一款僅使用少量 CPU 及記憶體的高效能攔截器。", + "message": "終於有一款高效能的封鎖工具。對 CPU 和記憶體的占用極低。", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "dashboardName": { @@ -40,11 +40,11 @@ "description": "appears as tab name in dashboard" }, "whitelistPageName": { - "message": "白名單", + "message": "受信任網站", "description": "appears as tab name in dashboard" }, "shortcutsPageName": { - "message": "快速鍵", + "message": "快捷鍵", "description": "appears as tab name in dashboard" }, "statsPageName": { @@ -72,11 +72,11 @@ "description": "English: Click: disable/enable uBlock₀ for this site.\n\nCtrl+click: disable uBlock₀ only on this page." }, "popupPowerSwitchInfo1": { - "message": "點擊:在此網站停用 uBlock₀ 。\n\nCtrl + 點擊:僅在此頁面停用 uBlock₀ 。", + "message": "點擊:在這個網站停用 uBlock₀ 。\n\nCtrl + 點擊:僅在這個頁面停用 uBlock₀ 。", "description": "Message to be read by screen readers" }, "popupPowerSwitchInfo2": { - "message": "點擊以在此網站啟用 uBlock₀ 。", + "message": "點擊以在這個網站啟用 uBlock₀。", "description": "Message to be read by screen readers" }, "popupBlockedRequestPrompt": { @@ -136,11 +136,11 @@ "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoPopups1": { - "message": "點擊以封鎖此網站的所有彈出式視窗", + "message": "點擊以封鎖這個網站的所有彈出式視窗", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoPopups2": { - "message": "點擊以解除封鎖此網站的所有彈出式視窗", + "message": "點擊以解除封鎖這個網站的所有彈出式視窗", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoLargeMedia": { @@ -164,7 +164,7 @@ "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoCosmeticFiltering2": { - "message": "點擊以啟用此網站的網頁元素過濾", + "message": "點擊以啟用這個網站的網頁元素過濾", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoRemoteFonts": { @@ -176,15 +176,15 @@ "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoRemoteFonts2": { - "message": "點擊以解除封鎖此網站的遠端字型", + "message": "點擊以解除封鎖這個網站的遠端字型", "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoScripting1": { - "message": "點擊以停用此網站的 JavaScript", + "message": "點擊以停用這個網站的 JavaScript", "description": "Tooltip for the no-scripting per-site switch" }, "popupTipNoScripting2": { - "message": "點擊以重新啟用此網站的 JavaScript ", + "message": "點擊以重新啟用此網站的 JavaScript", "description": "Tooltip for the no-scripting per-site switch" }, "popupNoPopups_v2": { @@ -356,7 +356,7 @@ "description": "Checkbox to let user access advanced, technical features" }, "settingsPrefetchingDisabledPrompt": { - "message": "停用「預先取回連結」(避免連接至已阻擋的網路請求)", + "message": "停用預先擷取功能(以避免對被封鎖的網路請求產生任何連線)", "description": "English: " }, "settingsHyperlinkAuditingDisabledPrompt": { @@ -364,7 +364,7 @@ "description": "English: " }, "settingsWebRTCIPAddressHiddenPrompt": { - "message": "防止 WebRTC 洩漏本機 IP 位址", + "message": "防止 WebRTC 洩漏本地 IP 位址", "description": "English: " }, "settingPerSiteSwitchGroup": { @@ -444,7 +444,7 @@ "description": "English: Parse and enforce Adblock+ element hiding filters." }, "3pParseAllABPHideFiltersInfo": { - "message": "「網頁元素過濾規則」用來隱藏網頁中被認為礙眼,且不能被以網路請求為基礎之過濾引擎所阻擋的元素。", + "message": "「網頁元素過濾規則」負責隱藏網頁中被認為礙眼,且不能被網路請求過濾引擎阻擋的元素。", "description": "Describes the purpose of the 'Parse and enforce cosmetic filters' feature." }, "3pIgnoreGenericCosmeticFilters": { @@ -480,11 +480,11 @@ "description": "Filter lists section name" }, "3pGroupMalware": { - "message": "惡意軟體防護及安全性", + "message": "惡意軟體保護及保安", "description": "Filter lists section name" }, "3pGroupSocial": { - "message": "社交小工具", + "message": "社交媒體小工具", "description": "Filter lists section name" }, "3pGroupCookies": { @@ -492,7 +492,7 @@ "description": "Filter lists section name" }, "3pGroupAnnoyances": { - "message": "嫌惡元素", + "message": "騷擾", "description": "Filter lists section name" }, "3pGroupMultipurpose": { @@ -512,7 +512,7 @@ "description": "The label for the checkbox used to import external filter lists" }, "3pExternalListsHint": { - "message": "每行一個網址。無效的網址將被忽略。", + "message": "每行一個網址。以「!」開頭的行將被忽略。無效的網址也將被忽略。", "description": "Short information about how to use the textarea to import external filter lists by URL" }, "3pExternalListObsolete": { @@ -524,7 +524,7 @@ "description": "used as a tooltip for eye icon beside a list" }, "3pLastUpdate": { - "message": "上次更新:{{ago}}。\n點擊此處以強制更新。", + "message": "最後更新:{{ago}}。", "description": "used as a tooltip for the clock icon beside a list" }, "3pUpdating": { @@ -536,11 +536,11 @@ "description": "used as a tooltip for error icon beside a list" }, "1pTrustWarning": { - "message": "切勿加入來歷不明的過濾規則。", + "message": "切勿添加來自不可信來源的過濾規則。", "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { - "message": "啟用自訂過濾器", + "message": "啟用我的自訂過濾規則", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { @@ -624,7 +624,7 @@ "description": "English: a sort option for list of rules." }, "rulesSortByDestination": { - "message": "目標", + "message": "目的地", "description": "English: a sort option for list of rules." }, "whitelistPrompt": { @@ -760,15 +760,15 @@ "description": "Label to identify a rule field" }, "loggerEntryDetailsContext": { - "message": "上下文", + "message": "來源", "description": "Label to identify a context field (typically a hostname)" }, "loggerEntryDetailsRootContext": { - "message": "根上下文", + "message": "主內容", "description": "Label to identify a root context field (typically a hostname)" }, "loggerEntryDetailsPartyness": { - "message": "第一方/第三方", + "message": "第一方/第三方", "description": "Label to identify a field providing partyness information" }, "loggerEntryDetailsType": { @@ -832,15 +832,15 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringFinderSentence1": { - "message": "在下列清單中找到靜態過濾規則 {{filter}}:", + "message": "在下列清單中找到靜態過濾規則 {{filter}}:", "description": "Below this sentence, the filter list(s) in which the filter was found" }, "loggerStaticFilteringFinderSentence2": { - "message": "無法在任何目前已啟用的過濾規則清單中找到靜態過濾規則", + "message": "無法在任何啟用的過濾清單中,找到靜態過濾規則 {{filter}}", "description": "Message to show when a filter cannot be found in any filter lists" }, "loggerSettingDiscardPrompt": { - "message": "未符合以下所有條件的記錄將會被自動捨棄:", + "message": "不符合以下任一狀況的記錄將會被自動清除:", "description": "Logger setting: A sentence to describe the purpose of the settings below" }, "loggerSettingPerEntryMaxAge": { @@ -848,7 +848,7 @@ "description": "A logger setting" }, "loggerSettingPerTabMaxLoads": { - "message": "每個分頁最多保留 {{input}} 次重新載入該頁所產生的記錄", + "message": "每個分頁最多保留 {{input}} 次內容加載產生的記錄", "description": "A logger setting" }, "loggerSettingPerTabMaxEntries": { @@ -856,7 +856,7 @@ "description": "A logger setting" }, "loggerSettingPerEntryLineCount": { - "message": "在垂直延展模式中每條記錄顯示 {{input}} 行", + "message": "在垂直延展的模式中每個項目顯示 {{input}} 行", "description": "A logger setting" }, "loggerSettingHideColumnsPrompt": { @@ -900,7 +900,7 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "建立新報告", + "message": "發出新報告", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { @@ -924,7 +924,7 @@ "description": "First paragraph of 'Questions and support' section in Support pane" }, "supportS3H": { - "message": "過濾器問題 / 網站被破壞", + "message": "過濾器問題 / 網站被搞壞", "description": "Header of 'Filter issues' section in Support pane" }, "supportS3P1": { @@ -936,7 +936,7 @@ "description": "Second paragraph of 'Filter issues' section in Support pane" }, "supportS3P3": { - "message": "小提示:請確定您的過濾器清單已經更新至最新版本。我們主要用「記錄器」來分析過濾器相關問題。", + "message": "小提示:請確定您的過濾器清單已經更新至最新版本。我們主要用 記錄器 來分析過濾器相關問題。", "description": "Third paragraph of 'Filter issues' section in Support pane" }, "supportS4H": { @@ -964,11 +964,11 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "為免給志願者帶來額外負擔,請先檢查問題有沒有被回報過,避免重複回報。", + "message": "為了避免太多人發出重複的報告拖垮志工,請先確認是否已經有人回報過您打算報告的問題。", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { - "message": "過濾器清單每天更新,請確保問題尚未在最新版本中解決。", + "message": "過濾器清單每天更新。請確認您的問題無法用最新的過濾器清單解決。", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S2": { @@ -992,11 +992,11 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "含有覆蓋物或其他滋擾物", + "message": "會覆蓋內容或有其他煩人的內容", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { - "message": "偵測到 uBlock Origin", + "message": "會偵測到您已安裝 uBlock Origin", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { @@ -1004,11 +1004,11 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "開啟 uBlock Origin 的時候運作不正常", + "message": "開啟 uBlock Origin 的時候網頁運作不正常", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { - "message": "會開啟不需要的分頁或視窗", + "message": "會開啟不想要的分頁或視窗", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option7": { @@ -1036,7 +1036,7 @@ "description": "" }, "aboutCode": { - "message": "原始碼(GPLv3)", + "message": "源碼(GPLv3)", "description": "English: Source code (GPLv3)" }, "aboutContributors": { @@ -1044,7 +1044,7 @@ "description": "English: Contributors" }, "aboutSourceCode": { - "message": "原始碼", + "message": "源碼", "description": "Link text to source code repo" }, "aboutTranslations": { @@ -1056,11 +1056,11 @@ "description": "Link text to uBO's own filter lists repo" }, "aboutDependencies": { - "message": "外部相依套件(與 GPLv3 相容):", + "message": "外部相依套件(與通用公眾授權條款第三版相容):", "description": "Shown in the About pane" }, "aboutCDNs": { - "message": "uBO 自家的過濾規則清單由下列 CDN 免費代管:", + "message": "uBO 自家的過濾規則清單代管於下列 CDN 中:", "description": "Shown in the About pane" }, "aboutCDNsInfo": { @@ -1096,7 +1096,7 @@ "description": "Message asking user to confirm reset" }, "errorCantConnectTo": { - "message": "網路錯誤:{{msg}}", + "message": "無法連線至 {{url}}", "description": "English: Network error: {{msg}}" }, "subscriberConfirm": { @@ -1144,7 +1144,7 @@ "description": "Firefox-specific: appears as 'uBlock₀ (off)'" }, "docblockedTitle": { - "message": "已封鎖頁面", + "message": "頁面已阻擋", "description": "Used as a title for the document-blocked page" }, "docblockedPrompt1": { @@ -1195,6 +1195,22 @@ "message": "被封鎖的網頁想要重新導向至其他網站。如果您選擇繼續,則會直接前往:{{url}}", "description": "Text warning about an incoming redirect" }, + "docblockedReasonLabel": { + "message": "理由:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "惡意程式碼", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "追蹤器", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "聲名狼藉", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "匯出至雲端儲存空間", "description": "tooltip" @@ -1240,7 +1256,7 @@ "description": "An entry in the browser's contextual menu" }, "contextMenuSubscribeToList": { - "message": "訂閱過濾規則清單…", + "message": "訂閱過濾器清單⋯", "description": "An entry in the browser's contextual menu" }, "contextMenuTemporarilyAllowLargeMediaElements": { @@ -1304,7 +1320,7 @@ "description": "Summary of number of errors as reported by the linter " }, "unprocessedRequestTooltip": { - "message": "無法在瀏覽器啟動時正確過濾頁面。請重新載入以確保過濾正常。", + "message": "無法在瀏覽器啟動的時候正確過濾。\n請重新載入頁面來確保過濾正確。", "description": "A warning which will appear in the popup panel if needed" }, "dummy": { diff -Nru ublock-origin-1.62.0+dfsg/src/about.html ublock-origin-1.67.0+dfsg/src/about.html --- ublock-origin-1.62.0+dfsg/src/about.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/about.html 2025-10-25 19:32:51.000000000 +0000 @@ -3,6 +3,7 @@ + uBlock — About diff -Nru ublock-origin-1.62.0+dfsg/src/advanced-settings.html ublock-origin-1.67.0+dfsg/src/advanced-settings.html --- ublock-origin-1.62.0+dfsg/src/advanced-settings.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/advanced-settings.html 2025-10-25 19:32:51.000000000 +0000 @@ -3,6 +3,7 @@ + @@ -13,7 +14,7 @@ - + diff -Nru ublock-origin-1.62.0+dfsg/src/asset-viewer.html ublock-origin-1.67.0+dfsg/src/asset-viewer.html --- ublock-origin-1.62.0+dfsg/src/asset-viewer.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/asset-viewer.html 2025-10-25 19:32:51.000000000 +0000 @@ -3,6 +3,7 @@ + @@ -11,7 +12,7 @@ - + diff -Nru ublock-origin-1.62.0+dfsg/src/blank.html ublock-origin-1.67.0+dfsg/src/blank.html --- ublock-origin-1.62.0+dfsg/src/blank.html 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/blank.html 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,11 @@ + + + + + + +uBO blank + + + + diff -Nru ublock-origin-1.62.0+dfsg/src/code-viewer.html ublock-origin-1.67.0+dfsg/src/code-viewer.html --- ublock-origin-1.62.0+dfsg/src/code-viewer.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/code-viewer.html 2025-10-25 19:32:51.000000000 +0000 @@ -3,6 +3,7 @@ + Code viewer diff -Nru ublock-origin-1.62.0+dfsg/src/css/codemirror.css ublock-origin-1.67.0+dfsg/src/css/codemirror.css --- ublock-origin-1.62.0+dfsg/src/css/codemirror.css 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/css/codemirror.css 2025-10-25 19:32:51.000000000 +0000 @@ -356,3 +356,9 @@ .CodeMirror-lintmarker[data-error="y"] > span:hover { display: initial; } + +/* https://github.com/uBlockOrigin/uBlock-issues/issues/3645 */ +.CodeMirror-vscrollbar { + pointer-events: initial !important; + } + diff -Nru ublock-origin-1.62.0+dfsg/src/css/common.css ublock-origin-1.67.0+dfsg/src/css/common.css --- ublock-origin-1.62.0+dfsg/src/css/common.css 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/css/common.css 2025-10-25 19:32:51.000000000 +0000 @@ -37,6 +37,7 @@ --default-gap-small: 12px; --default-gap-xsmall: 8px; --default-gap-xxsmall: 4px; + --button-font-size: max(calc(var(--font-size) * 0.875), 14px); } /* Common uBO styles */ @@ -79,13 +80,13 @@ appearance: none; -moz-appearance: none; -webkit-appearance: none; - border: 0; + border: var(--button-border-size) solid var(--ink-1); border-radius: var(--button-border-radius); background-color: var(--button-surface); color: var(--button-ink); display: inline-flex; fill: var(--button-ink); - font-size: max(calc(var(--font-size) * 0.875), 14px); + font-size: var(--button-font-size); justify-content: center; min-height: 36px; padding: 0 var(--font-size); @@ -192,7 +193,7 @@ height: 100%; margin: 0; min-width: var(--checkbox-size); - opacity: 0; + opacity: var(--native-control-opacity); position: absolute; width: 100%; } @@ -203,6 +204,7 @@ box-sizing: border-box; fill: none; height: 100%; + opacity: calc(1 - var(--native-control-opacity)); pointer-events: none; position: absolute; stroke: none; @@ -241,7 +243,7 @@ height: 100%; margin: 0; min-width: var(--checkbox-size); - opacity: 0; + opacity: var(--native-control-opacity); position: absolute; width: 100%; } @@ -249,6 +251,7 @@ background-color: transparent; box-sizing: border-box; height: 100%; + opacity: calc(1 - var(--native-control-opacity)); pointer-events: none; position: absolute; width: 100%; diff -Nru ublock-origin-1.62.0+dfsg/src/css/dashboard.css ublock-origin-1.67.0+dfsg/src/css/dashboard.css --- ublock-origin-1.62.0+dfsg/src/css/dashboard.css 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/css/dashboard.css 2025-10-25 19:32:51.000000000 +0000 @@ -1,4 +1,5 @@ html, body { + background-color: var(--surface-0); display: flex; flex-direction: column; height: 100vh; @@ -13,6 +14,7 @@ } #dashboard-nav { align-items: center; + background-color: var(--surface-1); border: 0; border-bottom: 1px solid var(--border-1); display: flex; diff -Nru ublock-origin-1.62.0+dfsg/src/css/document-blocked.css ublock-origin-1.67.0+dfsg/src/css/document-blocked.css --- ublock-origin-1.62.0+dfsg/src/css/document-blocked.css 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/css/document-blocked.css 2025-10-25 19:32:51.000000000 +0000 @@ -23,6 +23,9 @@ padding: var(--default-gap-xxlarge) var(--default-gap-small); justify-content: center; } +body.loading { + opacity: 0; + } :root.mobile body { padding: var(--default-gap-small); } @@ -70,7 +73,7 @@ } #theURL > p > span:first-of-type { display: block; - max-height: 6lh; + max-height: 3lh; overflow-y: auto; } :root.mobile #theURL > p > span:first-of-type { @@ -128,18 +131,22 @@ font-weight: bold; } -#whyex a { +.why-extra a { white-space: nowrap; } -#whyex ul { +.why-extra ul { display: flex; flex-direction: column; margin: 0; padding-inline-start: var(--default-gap-xsmall); } +details > *:not(summary) { + margin-inline-start: 1em; + } #urlskip a { display: block; + max-height: 3lh; overflow-y: auto; word-break: break-all; } @@ -161,11 +168,14 @@ } .filterList { - display: flex; -} -.filterList .filterListSupport[href=""] { + white-space: nowrap; + } +.filterList .filterListSupport[href="#"] { display: none; } +.filterList .filterListSupport:not([href="#"]) { + margin-inline-start: 0.25em; + } /* Small-screen devices */ :root.mobile button { diff -Nru ublock-origin-1.62.0+dfsg/src/css/epicker-ui.css ublock-origin-1.67.0+dfsg/src/css/epicker-ui.css --- ublock-origin-1.62.0+dfsg/src/css/epicker-ui.css 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/css/epicker-ui.css 2025-10-25 19:32:51.000000000 +0000 @@ -1,3 +1,7 @@ +:root { + --quit-button-size: max(4em, min(6em, calc(100vw / 8), calc(100vh / 8))); +} + html#ublock0-epicker, #ublock0-epicker body { background: transparent; @@ -16,7 +20,7 @@ border: 1px solid var(--border-2); box-sizing: border-box; cursor: default; - display: none; + display: flex; flex-direction: column; max-width: min(32rem, 100vw - 4px); min-width: min(24rem, 100vw - 4px); @@ -25,8 +29,21 @@ width: min(32rem, 100vw - 4px); z-index: 100; } -#ublock0-epicker:not(.zap) aside { - display: flex; +#ublock0-epicker.zap aside { + bottom: unset !important; + min-width: unset !important; + top: 50%; + transform: translateY(-50%); + width: unset !important; +} +#ublock0-epicker.zap aside > section, +#ublock0-epicker.zap aside > ul, +#ublock0-epicker.zap aside > #windowbar > div:not(#quit) { + display: none; +} +#ublock0-epicker.zap aside > #windowbar > #quit { + width: var(--quit-button-size); + height: var(--quit-button-size); } #ublock0-epicker:not(.paused) aside, #ublock0-epicker.minimized aside { Binary files /srv/release.debian.org/tmp/En7nkbHWiS/ublock-origin-1.62.0+dfsg/src/css/fonts/Inter/Inter-Regular.woff2 and /srv/release.debian.org/tmp/loyMF0iGQH/ublock-origin-1.67.0+dfsg/src/css/fonts/Inter/Inter-Regular.woff2 differ Binary files /srv/release.debian.org/tmp/En7nkbHWiS/ublock-origin-1.62.0+dfsg/src/css/fonts/Inter/Inter-SemiBold.woff2 and /srv/release.debian.org/tmp/loyMF0iGQH/ublock-origin-1.67.0+dfsg/src/css/fonts/Inter/Inter-SemiBold.woff2 differ diff -Nru ublock-origin-1.62.0+dfsg/src/css/themes/default.css ublock-origin-1.67.0+dfsg/src/css/themes/default.css --- ublock-origin-1.62.0+dfsg/src/css/themes/default.css 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/css/themes/default.css 2025-10-25 19:32:51.000000000 +0000 @@ -381,10 +381,8 @@ --logger-scriptlet-surface: rgb(var(--yellow-30) / 40%); } -:root.dark input, -:root.dark select, -:root.dark textarea { - color-scheme: dark; +:root.dark { + color-scheme: dark light; } /* @@ -410,8 +408,11 @@ --fieldset-header-surface: transparent; --fieldset-header-ink: var(--ink-2); + --native-control-opacity: 0; + --button-ink: var(--ink-1); --button-surface: rgb(var(--button-surface-rgb)); + --button-border-size: 0; --button-border-radius: 5px; --button-preferred-ink: var(--accent-ink-1); --button-preferred-surface: var(--accent-surface-1); @@ -455,13 +456,20 @@ --popup-cell-block-surface: rgb(var(--popup-cell-block-surface-rgb)); --popup-power-ink: rgb(var(--popup-power-ink-rgb)); --popup-toolbar-surface: rgb(var(--primary-80) / 15%); - --popup-toolbar-surface-hover: rgb(var(--primary-80) / 20%); + --popup-toolbar-surface-hover: rgb(var(--primary-80) / 30%); --popup-ruleset-tool-ink: var(--ink-1); --popup-ruleset-tool-surface: rgb(var(--primary-80) / 15%); --popup-ruleset-tool-surface-hover: rgb(var(--primary-80) / 20%); --popup-ruleset-tool-shadow: transparent; } +@media (prefers-contrast: more) { + :root { + --native-control-opacity: 1; + --button-border-size: 1px; + } +} + /* * Rule colors * */ diff -Nru ublock-origin-1.62.0+dfsg/src/dashboard.html ublock-origin-1.67.0+dfsg/src/dashboard.html --- ublock-origin-1.62.0+dfsg/src/dashboard.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/dashboard.html 2025-10-25 19:32:51.000000000 +0000 @@ -3,12 +3,13 @@ + - + @@ -36,7 +37,7 @@

    - + diff -Nru ublock-origin-1.62.0+dfsg/src/devtools.html ublock-origin-1.67.0+dfsg/src/devtools.html --- ublock-origin-1.62.0+dfsg/src/devtools.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/devtools.html 2025-10-25 19:32:51.000000000 +0000 @@ -3,6 +3,7 @@ + uBlock — Dev tools @@ -33,7 +34,7 @@
    -
    +
    diff -Nru ublock-origin-1.62.0+dfsg/src/document-blocked.html ublock-origin-1.67.0+dfsg/src/document-blocked.html --- ublock-origin-1.62.0+dfsg/src/document-blocked.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/document-blocked.html 2025-10-25 19:32:51.000000000 +0000 @@ -3,14 +3,15 @@ + - + - +
    exclamation-triangle @@ -24,14 +25,7 @@
    -
    -

    _

    -

     

    - -
    +
    @@ -46,14 +40,28 @@ - +
    + diff -Nru ublock-origin-1.62.0+dfsg/src/dyna-rules.html ublock-origin-1.67.0+dfsg/src/dyna-rules.html --- ublock-origin-1.62.0+dfsg/src/dyna-rules.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/dyna-rules.html 2025-10-25 19:32:51.000000000 +0000 @@ -3,6 +3,7 @@ + uBlock — Dynamic filtering rules diff -Nru ublock-origin-1.62.0+dfsg/src/js/1p-filters.js ublock-origin-1.67.0+dfsg/src/js/1p-filters.js --- ublock-origin-1.62.0+dfsg/src/js/1p-filters.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/1p-filters.js 2025-10-25 19:32:51.000000000 +0000 @@ -97,7 +97,7 @@ const enabled = qs$('#enableMyFilters input').checked; return { enabled, - trusted: enabled && qs$('#trustMyFilters input').checked, + trusted: qs$('#trustMyFilters input').checked, filters: getEditorText(), }; } @@ -111,12 +111,12 @@ } function getEditorText() { - const text = cmEditor.getValue().replace(/\s+$/, ''); + const text = cmEditor.getValue().trimEnd(); return text === '' ? text : `${text}\n`; } function setEditorText(text) { - cmEditor.setValue(text.replace(/\s+$/, '') + '\n\n'); + cmEditor.setValue(`${text.trimEnd()}\n\n`); } /******************************************************************************/ @@ -128,7 +128,6 @@ qs$('#userFiltersApply').disabled = !changed; qs$('#userFiltersRevert').disabled = !changed; const enabled = qs$('#enableMyFilters input').checked; - dom.attr('#trustMyFilters .input.checkbox', 'disabled', enabled ? null : ''); const trustedbefore = cmEditor.getOption('trustedSource'); const trustedAfter = enabled && qs$('#trustMyFilters input').checked; if ( trustedAfter === trustedbefore ) { return; } diff -Nru ublock-origin-1.62.0+dfsg/src/js/3p-filters.js ublock-origin-1.67.0+dfsg/src/js/3p-filters.js --- ublock-origin-1.62.0+dfsg/src/js/3p-filters.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/3p-filters.js 2025-10-25 19:32:51.000000000 +0000 @@ -30,10 +30,6 @@ const reValidExternalList = /^[a-z-]+:\/\/(?:\S+\/\S*|\/\S+)/m; const recentlyUpdated = 1 * 60 * 60 * 1000; // 1 hour -// https://eslint.org/docs/latest/rules/no-prototype-builtins -const hasOwnProperty = (o, p) => - Object.prototype.hasOwnProperty.call(o, p); - let listsetDetails = {}; /******************************************************************************/ @@ -246,7 +242,7 @@ } for ( const [ listkey, listDetails ] of Object.entries(response.available) ) { let groupkey = listDetails.group2 || listDetails.group; - if ( hasOwnProperty(listTree, groupkey) === false ) { + if ( Object.hasOwn(listTree, groupkey) === false ) { groupkey = 'unknown'; } const groupDetails = listTree[groupkey]; @@ -603,7 +599,7 @@ const toRemove = []; for ( const liEntry of qsa$('#lists .listEntry[data-role="leaf"]') ) { const listkey = liEntry.dataset.key; - if ( hasOwnProperty(listsetDetails.available, listkey) === false ) { + if ( Object.hasOwn(listsetDetails.available, listkey) === false ) { continue; } const listDetails = listsetDetails.available[listkey]; diff -Nru ublock-origin-1.62.0+dfsg/src/js/about.js ublock-origin-1.67.0+dfsg/src/js/about.js --- ublock-origin-1.62.0+dfsg/src/js/about.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/about.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - import { dom } from './dom.js'; /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/src/js/advanced-settings.js ublock-origin-1.67.0+dfsg/src/js/advanced-settings.js --- ublock-origin-1.62.0+dfsg/src/js/advanced-settings.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/advanced-settings.js 2025-10-25 19:32:51.000000000 +0000 @@ -21,8 +21,6 @@ /* global CodeMirror, uBlockDashboard */ -'use strict'; - import { dom, qs$ } from './dom.js'; /******************************************************************************/ @@ -90,7 +88,7 @@ const arrayFromObject = function(o) { const out = []; for ( const k in o ) { - if ( o.hasOwnProperty(k) === false ) { continue; } + if ( Object.hasOwn(o, k) === false ) { continue; } out.push([ k, `${o[k]}` ]); } return out; diff -Nru ublock-origin-1.62.0+dfsg/src/js/arglist-parser.js ublock-origin-1.67.0+dfsg/src/js/arglist-parser.js --- ublock-origin-1.62.0+dfsg/src/js/arglist-parser.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/arglist-parser.js 2025-10-25 19:32:51.000000000 +0000 @@ -32,7 +32,7 @@ this.transform = false; this.failed = false; this.reWhitespaceStart = /^\s+/; - this.reWhitespaceEnd = /\s+$/; + this.reWhitespaceEnd = /(?:^|\S)(\s+)$/; this.reOddTrailingEscape = /(?:^|[^\\])(?:\\\\)*\\$/; this.reTrailingEscapeChars = /\\+$/; } @@ -90,7 +90,7 @@ } rightWhitespaceCount(s) { const match = this.reWhitespaceEnd.exec(s); - return match === null ? 0 : match[0].length; + return match === null ? 0 : match[1].length; } indexOfNextArgSeparator(pattern, separatorCode) { this.argBeg = this.argEnd = separatorCode !== this.separatorCode diff -Nru ublock-origin-1.62.0+dfsg/src/js/asset-viewer.js ublock-origin-1.67.0+dfsg/src/js/asset-viewer.js --- ublock-origin-1.62.0+dfsg/src/js/asset-viewer.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/asset-viewer.js 2025-10-25 19:32:51.000000000 +0000 @@ -21,12 +21,8 @@ /* global CodeMirror, uBlockDashboard */ -'use strict'; - -/******************************************************************************/ - -import { dom, qs$ } from './dom.js'; import './codemirror/ubo-static-filtering.js'; +import { dom, qs$ } from './dom.js'; /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/src/js/assets.js ublock-origin-1.67.0+dfsg/src/js/assets.js --- ublock-origin-1.62.0+dfsg/src/js/assets.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/assets.js 2025-10-25 19:32:51.000000000 +0000 @@ -47,9 +47,6 @@ /******************************************************************************/ -const hasOwnProperty = (o, p) => - Object.prototype.hasOwnProperty.call(o, p); - const stringIsNotEmpty = s => typeof s === 'string' && s !== ''; const parseExpires = s => { @@ -319,7 +316,7 @@ xhr.responseType = options.responseType || 'text'; xhr.send(); timeoutTimer.on({ sec: timeoutAfter }); - } catch (e) { + } catch { onErrorEvent.call(xhr); } @@ -396,7 +393,7 @@ const toParsedURL = url => { try { return new URL(url.trim()); - } catch (ex) { + } catch { } }; @@ -622,7 +619,7 @@ Array.from(Object.entries(newDict)) .filter(a => a[1].content === 'filters' && a[1].off === undefined) .map(a => a[0]); - } catch (ex) { + } catch { } if ( newDict instanceof Object === false ) { return; } @@ -735,7 +732,7 @@ } if ( bin instanceof Object === false ) { return reportBack(''); } - if ( hasOwnProperty(bin, internalKey) === false ) { return reportBack(''); } + if ( Object.hasOwn(bin, internalKey) === false ) { return reportBack(''); } const entry = assetCacheRegistry[assetKey]; if ( entry === undefined ) { return reportBack(''); } @@ -912,6 +909,13 @@ return readUserAsset(assetKey); } + // https://github.com/uBlockOrigin/uBlock-issues/issues/3761 + if ( µb.readyToFilter !== true ) { + if ( options.favorLocal === undefined ) { + options.favorLocal = true; + } + } + let assetDetails = {}; const reportBack = (content, url = '', err = undefined) => { @@ -958,6 +962,7 @@ let error = 'ENOTFOUND'; for ( const contentURL of contentURLs ) { + ubolog(`Fetching ${contentURL} from remote server `); const details = assetDetails.content === 'filters' ? await assets.fetchFilterList(contentURL) : await assets.fetchText(contentURL); @@ -1216,6 +1221,9 @@ } if ( Array.isArray(out.cdnURLs) === false ) { return; } if ( out.cdnURLs.length === 0 ) { return; } + if ( Array.isArray(assetEntry.patchURLs) ) { + out.patchURLs = assetEntry.patchURLs.slice(); + } return out; }; @@ -1244,10 +1252,8 @@ ubolog('Diff updater: cycle start'); return new Promise(resolve => { let pendingOps = 0; - const bc = new globalThis.BroadcastChannel('diffUpdater'); const terminate = error => { worker.terminate(); - bc.close(); resolve(); if ( typeof error !== 'string' ) { return; } ubolog(`Diff updater: terminate because ${error}`); @@ -1260,14 +1266,15 @@ if ( metadata.diffPath === data.patchPath ) { return; } assetCacheSetDetails(data.assetKey, metadata); }; - bc.onmessage = ev => { + const worker = new Worker('js/diff-updater.js'); + worker.onmessage = ev => { const data = ev.data || {}; if ( data.what === 'ready' ) { ubolog('Diff updater: hard updating', toHardUpdate.map(v => v.assetKey).join()); while ( toHardUpdate.length !== 0 ) { const assetDetails = toHardUpdate.shift(); assetDetails.fetch = true; - bc.postMessage(assetDetails); + worker.postMessage(assetDetails); pendingOps += 1; } return; @@ -1284,7 +1291,7 @@ data.text = result.content || ''; data.status = undefined; checkAndCorrectDiffPath(data); - bc.postMessage(data); + worker.postMessage(data); }); return; } @@ -1320,7 +1327,7 @@ if ( pendingOps === 0 && toSoftUpdate.length !== 0 ) { ubolog('Diff updater: soft updating', toSoftUpdate.map(v => v.assetKey).join()); while ( toSoftUpdate.length !== 0 ) { - bc.postMessage(toSoftUpdate.shift()); + worker.postMessage(toSoftUpdate.shift()); pendingOps += 1; } } @@ -1328,7 +1335,6 @@ ubolog('Diff updater: cycle complete'); terminate(); }; - const worker = new Worker('js/diff-updater.js'); }).catch(reason => { ubolog(`Diff updater: ${reason}`); }); diff -Nru ublock-origin-1.62.0+dfsg/src/js/background.js ublock-origin-1.67.0+dfsg/src/js/background.js --- ublock-origin-1.62.0+dfsg/src/js/background.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/background.js 2025-10-25 19:32:51.000000000 +0000 @@ -53,7 +53,7 @@ cacheStorageCompression: true, cacheStorageCompressionThreshold: 65536, cacheStorageMultithread: 2, - cacheControlForFirefox1376932: 'no-cache, no-store, must-revalidate', + cacheControlForFirefox1376932: 'unset', cloudStorageCompression: true, cnameIgnoreList: 'unset', cnameIgnore1stParty: true, @@ -180,8 +180,8 @@ // Read-only systemSettings: { - compiledMagic: 57, // Increase when compiled format changes - selfieMagic: 58, // Increase when selfie format changes + compiledMagic: 60, // Increase when compiled format changes + selfieMagic: 60, // Increase when selfie format changes }, // https://github.com/uBlockOrigin/uBlock-issues/issues/759#issuecomment-546654501 diff -Nru ublock-origin-1.62.0+dfsg/src/js/base64-custom.js ublock-origin-1.67.0+dfsg/src/js/base64-custom.js --- ublock-origin-1.62.0+dfsg/src/js/base64-custom.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/base64-custom.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ // Custom base64 codecs. These codecs are meant to encode/decode typed arrays diff -Nru ublock-origin-1.62.0+dfsg/src/js/benchmarks.js ublock-origin-1.67.0+dfsg/src/js/benchmarks.js --- ublock-origin-1.62.0+dfsg/src/js/benchmarks.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/benchmarks.js 2025-10-25 19:32:51.000000000 +0000 @@ -89,7 +89,7 @@ if ( details.content.startsWith('[') ) { try { requests = JSON.parse(details.content); - } catch(ex) { + } catch { } } else { const lineIter = new LineIterator(details.content); @@ -99,7 +99,7 @@ if ( line === '' ) { continue; } try { parsed.push(JSON.parse(line)); - } catch(ex) { + } catch { parsed.length = 0; break; } @@ -183,7 +183,7 @@ if ( r === 1 ) { blockCount += 1; } else if ( r === 2 ) { allowCount += 1; } if ( r !== 1 ) { - if ( sfne.transformRequest(fctxt) ) { + if ( sfne.transformURL(fctxt) ) { redirectCount += 1; } if ( sfne.hasQuery(fctxt) ) { @@ -321,7 +321,6 @@ frameId: undefined, hostname: '', domain: '', - entity: '', }; const options = { noSpecificCosmeticFiltering: false, diff -Nru ublock-origin-1.62.0+dfsg/src/js/biditrie.js ublock-origin-1.67.0+dfsg/src/js/biditrie.js --- ublock-origin-1.62.0+dfsg/src/js/biditrie.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/biditrie.js 2025-10-25 19:32:51.000000000 +0000 @@ -24,13 +24,16 @@ A BidiTrieContainer is mostly a large buffer in which distinct but related tries are stored. The memory layout of the buffer is as follow: - 0-2047: haystack section - 2048-2051: number of significant characters in the haystack - 2052-2055: offset to start of trie data section (=> trie0) - 2056-2059: offset to end of trie data section (=> trie1) - 2060-2063: offset to start of character data section (=> char0) - 2064-2067: offset to end of character data section (=> char1) - 2068: start of trie data section + 0-8192: haystack section + 8192-8195: number of significant characters in the haystack + 8196-8199: offset to start of trie data section (=> trie0) + 8200-8203: offset to end of trie data section (=> trie1) + 8204-8207: offset to start of character data section (=> char0) + 8208-8211: offset to end of character data section (=> char1) + 8212-8215: offset to left index result (=> result_l) + 8216-8219: offset to right index result (=> result_r) + 8220-8223: offset to extra unit result (=> result_iu) + 8224: start of trie data section +--------------+ Normal cell: | And | If "Segment info" matches: @@ -93,18 +96,19 @@ */ +const VERSION = 2; const PAGE_SIZE = 65536*2; const HAYSTACK_START = 0; -const HAYSTACK_SIZE = 2048; // i32 / i8 -const HAYSTACK_SIZE_SLOT = HAYSTACK_SIZE >>> 2; // 512 / 2048 -const TRIE0_SLOT = HAYSTACK_SIZE_SLOT + 1; // 513 / 2052 -const TRIE1_SLOT = HAYSTACK_SIZE_SLOT + 2; // 514 / 2056 -const CHAR0_SLOT = HAYSTACK_SIZE_SLOT + 3; // 515 / 2060 -const CHAR1_SLOT = HAYSTACK_SIZE_SLOT + 4; // 516 / 2064 -const RESULT_L_SLOT = HAYSTACK_SIZE_SLOT + 5; // 517 / 2068 -const RESULT_R_SLOT = HAYSTACK_SIZE_SLOT + 6; // 518 / 2072 -const RESULT_IU_SLOT = HAYSTACK_SIZE_SLOT + 7; // 519 / 2076 -const TRIE0_START = HAYSTACK_SIZE_SLOT + 8 << 2; // 2080 +const HAYSTACK_SIZE = 8192; // i32 / i8 +const HAYSTACK_SIZE_SLOT = HAYSTACK_SIZE >>> 2; // 2048 / 8192 +const TRIE0_SLOT = HAYSTACK_SIZE_SLOT + 1; // 2049 / 8196 +const TRIE1_SLOT = HAYSTACK_SIZE_SLOT + 2; // 2050 / 8200 +const CHAR0_SLOT = HAYSTACK_SIZE_SLOT + 3; // 2051 / 8204 +const CHAR1_SLOT = HAYSTACK_SIZE_SLOT + 4; // 2052 / 8208 +const RESULT_L_SLOT = HAYSTACK_SIZE_SLOT + 5; // 2053 / 8212 +const RESULT_R_SLOT = HAYSTACK_SIZE_SLOT + 6; // 2054 / 8216 +const RESULT_IU_SLOT = HAYSTACK_SIZE_SLOT + 7; // 2055 / 8220 +const TRIE0_START = HAYSTACK_SIZE_SLOT + 8 << 2; // 8224 const CELL_BYTE_LENGTH = 12; const MIN_FREE_CELL_BYTE_LENGTH = CELL_BYTE_LENGTH * 8; @@ -156,28 +160,21 @@ // Public methods //-------------------------------------------------------------------------- - get haystackLen() { + getHaystackLen() { return this.buf32[HAYSTACK_SIZE_SLOT]; } - set haystackLen(v) { + setHaystackLen(v) { + if ( v > HAYSTACK_SIZE ) { + v = HAYSTACK_SIZE; + } this.buf32[HAYSTACK_SIZE_SLOT] = v; + return v; } - reset(details) { - if ( - details instanceof Object && - typeof details.byteLength === 'number' && - typeof details.char0 === 'number' - ) { - if ( details.byteLength > this.buf8.byteLength ) { - this.reallocateBuf(details.byteLength); - } - this.buf32[CHAR0_SLOT] = details.char0; - } + reset() { this.buf32[TRIE1_SLOT] = this.buf32[TRIE0_SLOT]; this.buf32[CHAR1_SLOT] = this.buf32[CHAR0_SLOT]; - this.lastStored = ''; this.lastStoredLen = this.lastStoredIndex = 0; } @@ -571,23 +568,22 @@ this.buf32[iboundary+BCELL_EXTRA] = v; } - optimize(shrink = false) { - if ( shrink ) { - this.shrinkBuf(); - } - return { - byteLength: this.buf8.byteLength, - char0: this.buf32[CHAR0_SLOT], - }; + optimize() { + this.shrinkBuf(); } toSelfie() { const buf32 = this.buf32.subarray(0, this.buf32[CHAR1_SLOT] + 3 >>> 2); - return { buf32, checksum: i32Checksum(buf32) }; + return { + version: VERSION, + buf32, + checksum: i32Checksum(buf32), + }; } fromSelfie(selfie) { if ( typeof selfie !== 'object' || selfie === null ) { return false; } + if ( selfie.version !== VERSION ) { return false; } if ( selfie.buf32 instanceof Uint32Array === false ) { return false; } if ( selfie.checksum !== i32Checksum(selfie.buf32) ) { return false; } const byteLength = selfie.buf32.length << 2; diff -Nru ublock-origin-1.62.0+dfsg/src/js/cachestorage.js ublock-origin-1.67.0+dfsg/src/js/cachestorage.js --- ublock-origin-1.62.0+dfsg/src/js/cachestorage.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/cachestorage.js 2025-10-25 19:32:51.000000000 +0000 @@ -44,10 +44,6 @@ let fastCache = 'indexedDB'; -// https://eslint.org/docs/latest/rules/no-prototype-builtins -const hasOwnProperty = (o, p) => - Object.prototype.hasOwnProperty.call(o, p); - /******************************************************************************* * * Extension storage @@ -76,7 +72,7 @@ if ( found.length === wanted.length ) { return; } const missing = []; for ( const key of wanted ) { - if ( hasOwnProperty(outbin, key) ) { continue; } + if ( Object.hasOwn(outbin, key) ) { continue; } missing.push(key); } return missing; @@ -118,7 +114,7 @@ if ( argbin instanceof Object === false ) { return; } if ( Array.isArray(argbin) ) { return; } for ( const key of wanted ) { - if ( hasOwnProperty(argbin, key) === false ) { continue; } + if ( Object.hasOwn(argbin, key) === false ) { continue; } outbin[key] = argbin[key]; } }).then(( ) => { @@ -187,7 +183,7 @@ }, select(api) { - if ( hasOwnProperty(cacheAPIs, api) === false ) { return fastCache; } + if ( Object.hasOwn(cacheAPIs, api) === false ) { return fastCache; } fastCache = api; for ( const k of Object.keys(cacheAPIs) ) { if ( k === api ) { continue; } @@ -480,7 +476,7 @@ try { const db = ev.target.result; db.createObjectStore(STORAGE_NAME, { keyPath: 'key' }); - } catch(ex) { + } catch { req.onerror(); } }; @@ -672,7 +668,7 @@ } if ( argbin instanceof Object && Array.isArray(argbin) === false ) { for ( const key of keys ) { - if ( hasOwnProperty(outbin, key) ) { continue; } + if ( Object.hasOwn(outbin, key) ) { continue; } outbin[key] = argbin[key]; } } diff -Nru ublock-origin-1.62.0+dfsg/src/js/click2load.js ublock-origin-1.67.0+dfsg/src/js/click2load.js --- ublock-origin-1.62.0+dfsg/src/js/click2load.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/click2load.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/src/js/cloud-ui.js ublock-origin-1.67.0+dfsg/src/js/cloud-ui.js --- ublock-origin-1.62.0+dfsg/src/js/cloud-ui.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/cloud-ui.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,12 +19,8 @@ Home: https://github.com/gorhill/uBlock */ -/* global faIconsInit */ - -'use strict'; - -import { i18n, i18n$ } from './i18n.js'; import { dom, qs$ } from './dom.js'; +import { i18n, i18n$ } from './i18n.js'; import { faIconsInit } from './fa-icons.js'; /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/src/js/code-viewer.js ublock-origin-1.67.0+dfsg/src/js/code-viewer.js --- ublock-origin-1.62.0+dfsg/src/js/code-viewer.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/code-viewer.js 2025-10-25 19:32:51.000000000 +0000 @@ -21,10 +21,6 @@ /* globals CodeMirror, uBlockDashboard, beautifier */ -'use strict'; - -/******************************************************************************/ - import { dom, qs$ } from './dom.js'; import { getActualTheme } from './theme.js'; @@ -39,6 +35,7 @@ gutters: [ 'CodeMirror-linenumbers' ], lineNumbers: true, lineWrapping: true, + maximizable: false, matchBrackets: true, styleActiveLine: { nonEmpty: true, @@ -117,25 +114,25 @@ } }; switch ( mime ) { - case 'text/css': - text = beautifier.css(text, beautifierOptions); - break; - case 'text/html': - case 'application/xhtml+xml': - case 'application/xml': - case 'image/svg+xml': - text = beautifier.html(text, beautifierOptions); - break; - case 'text/javascript': - case 'application/javascript': - case 'application/x-javascript': - text = beautifier.js(text, beautifierOptions); - break; - case 'application/json': - text = beautifier.js(text, beautifierOptions); - break; - default: - break; + case 'text/css': + text = beautifier.css(text, beautifierOptions); + break; + case 'text/html': + case 'application/xhtml+xml': + case 'application/xml': + case 'image/svg+xml': + text = beautifier.html(text, beautifierOptions); + break; + case 'text/javascript': + case 'application/javascript': + case 'application/x-javascript': + text = beautifier.js(text, beautifierOptions); + break; + case 'application/json': + text = beautifier.js(text, beautifierOptions); + break; + default: + break; } return { mime, text }; } @@ -182,7 +179,7 @@ const url = new URL(resourceURL, currentURL || undefined); url.hash = ''; afterURL = url.href; - } catch(ex) { + } catch { } if ( afterURL === undefined ) { return; } } else { diff -Nru ublock-origin-1.62.0+dfsg/src/js/codemirror/search-thread.js ublock-origin-1.67.0+dfsg/src/js/codemirror/search-thread.js --- ublock-origin-1.62.0+dfsg/src/js/codemirror/search-thread.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/codemirror/search-thread.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ (( ) => { @@ -43,7 +41,7 @@ let reSearch; try { reSearch = new RegExp(details.pattern, details.flags); - } catch(ex) { + } catch { return; } @@ -88,11 +86,14 @@ content = msg.content; break; - case 'doSearch': + case 'doSearch': { const response = doSearch(msg); self.postMessage({ id: msg.id, response }); break; } + default: + break; + } }; return; diff -Nru ublock-origin-1.62.0+dfsg/src/js/codemirror/search.js ublock-origin-1.67.0+dfsg/src/js/codemirror/search.js --- ublock-origin-1.62.0+dfsg/src/js/codemirror/search.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/codemirror/search.js 2025-10-25 19:32:51.000000000 +0000 @@ -226,7 +226,7 @@ query = re.source; flags = re.flags; } - catch (e) { + catch { reParsed = null; } } diff -Nru ublock-origin-1.62.0+dfsg/src/js/codemirror/ubo-dynamic-filtering.js ublock-origin-1.67.0+dfsg/src/js/codemirror/ubo-dynamic-filtering.js --- ublock-origin-1.62.0+dfsg/src/js/codemirror/ubo-dynamic-filtering.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/codemirror/ubo-dynamic-filtering.js 2025-10-25 19:32:51.000000000 +0000 @@ -21,8 +21,6 @@ /* global CodeMirror */ -'use strict'; - CodeMirror.defineMode('ubo-dynamic-filtering', ( ) => { const validSwitches = new Set([ @@ -69,7 +67,7 @@ hnValidator.hostname = '_'; try { hnValidator.hostname = hnin; - } catch(_) { + } catch { return false; } const hnout = hnValidator.hostname; diff -Nru ublock-origin-1.62.0+dfsg/src/js/codemirror/ubo-static-filtering.js ublock-origin-1.67.0+dfsg/src/js/codemirror/ubo-static-filtering.js --- ublock-origin-1.62.0+dfsg/src/js/codemirror/ubo-static-filtering.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/codemirror/ubo-static-filtering.js 2025-10-25 19:32:51.000000000 +0000 @@ -25,6 +25,7 @@ import * as sfp from '../static-filtering-parser.js'; import { dom, qs$ } from '../dom.js'; +import { tokenizableStrFromRegex } from '../regex-analyzer.js'; /******************************************************************************/ @@ -67,6 +68,8 @@ ) !== 0; }; + const reGoodRegexToken = /[^\x01%0-9A-Za-z][%0-9A-Za-z]{7,}|[^\x01%0-9A-Za-z][%0-9A-Za-z]{1,6}[^\x01%0-9A-Za-z]/; + const colorFromAstNode = mode => { if ( mode.astParser.nodeIsEmptyString(mode.currentWalkerNode) ) { return '+'; } if ( nodeHasError(mode) ) { return 'error'; } @@ -119,7 +122,9 @@ case sfp.NODE_TYPE_NET_PATTERN: if ( mode.astWalker.canGoDown() ) { break; } if ( mode.astParser.isRegexPattern() ) { - if ( mode.astParser.getNodeFlags(mode.currentWalkerNode, sfp.NODE_FLAG_PATTERN_UNTOKENIZABLE) !== 0 ) { + const s = mode.astParser.getNodeString(mode.currentWalkerNode); + const tokenizable = tokenizableStrFromRegex(s); + if ( reGoodRegexToken.test(tokenizable) === false ) { return 'variable warning'; } return 'variable notice'; diff -Nru ublock-origin-1.62.0+dfsg/src/js/commands.js ublock-origin-1.67.0+dfsg/src/js/commands.js --- ublock-origin-1.62.0+dfsg/src/js/commands.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/commands.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,12 +19,8 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - -import µb from './background.js'; import { hostnameFromURI } from './uri-utils.js'; +import µb from './background.js'; /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/src/js/console.js ublock-origin-1.67.0+dfsg/src/js/console.js --- ublock-origin-1.62.0+dfsg/src/js/console.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/console.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ function ubologSet(state = false) { diff -Nru ublock-origin-1.62.0+dfsg/src/js/contentscript-extra.js ublock-origin-1.67.0+dfsg/src/js/contentscript-extra.js --- ublock-origin-1.62.0+dfsg/src/js/contentscript-extra.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/contentscript-extra.js 2025-10-25 19:32:51.000000000 +0000 @@ -99,6 +99,7 @@ this.reValue = regexFromString(task[1].value, true); } transpose(node, output) { + if ( typeof node.getAttributeNames !== 'function' ) { return; } const attrs = node.getAttributeNames(); for ( const attr of attrs ) { if ( this.reAttr.test(attr) === false ) { continue; } @@ -508,7 +509,7 @@ prime(input) { try { return super.prime(input); - } catch (ex) { + } catch { } return []; } diff -Nru ublock-origin-1.62.0+dfsg/src/js/contentscript.js ublock-origin-1.67.0+dfsg/src/js/contentscript.js --- ublock-origin-1.62.0+dfsg/src/js/contentscript.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/contentscript.js 2025-10-25 19:32:51.000000000 +0000 @@ -125,7 +125,7 @@ ) { context = context.parent; } - } catch(ex) { + } catch { } vAPI.effectiveSelf = context; } @@ -360,7 +360,7 @@ if ( addedNodes.length === 0 && removedNodes === false ) { return; } for ( const listener of getListenerIterator() ) { try { listener.onDOMChanged(addedNodes, removedNodes); } - catch (ex) { } + catch { } } addedNodes.length = 0; removedNodes = false; @@ -422,7 +422,7 @@ listenerIteratorDirty = true; if ( domLayoutObserver === undefined ) { return; } try { listener.onDOMCreated(); } - catch (ex) { } + catch { } startMutationObserver(); }; @@ -450,7 +450,7 @@ const start = function() { for ( const listener of getListenerIterator() ) { try { listener.onDOMCreated(); } - catch (ex) { } + catch { } } startMutationObserver(); }; @@ -1312,7 +1312,7 @@ vAPI.messaging.send('contentscript', { what: 'retrieveContentScriptParameters', url: vAPI.effectiveSelf.location.href, - needScriptlets: typeof self.uBO_scriptletsInjected !== 'string', + needScriptlets: self.uBO_scriptletsInjected === undefined, }).then(response => { onResponseReady(response); }); diff -Nru ublock-origin-1.62.0+dfsg/src/js/contextmenu.js ublock-origin-1.67.0+dfsg/src/js/contextmenu.js --- ublock-origin-1.62.0+dfsg/src/js/contextmenu.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/contextmenu.js 2025-10-25 19:32:51.000000000 +0000 @@ -91,7 +91,7 @@ try { parsedURL = new URL(details.linkUrl); } - catch(ex) { + catch { } if ( parsedURL instanceof URL === false ) { return; } const url = parsedURL.searchParams.get('location'); diff -Nru ublock-origin-1.62.0+dfsg/src/js/cosmetic-filtering.js ublock-origin-1.67.0+dfsg/src/js/cosmetic-filtering.js --- ublock-origin-1.62.0+dfsg/src/js/cosmetic-filtering.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/cosmetic-filtering.js 2025-10-25 19:32:51.000000000 +0000 @@ -23,6 +23,7 @@ import { MRUCache } from './mrucache.js'; import { StaticExtFilteringHostnameDB } from './static-ext-filtering-db.js'; +import { entityFromHostname } from './uri-utils.js'; import logger from './logger.js'; import µb from './background.js'; @@ -234,7 +235,7 @@ }); // specific filters - this.specificFilters = new StaticExtFilteringHostnameDB(2); + this.specificFilters = new StaticExtFilteringHostnameDB(); // low generic cosmetic filters: map of hash => stringified selector list this.lowlyGeneric = new Map(); @@ -253,16 +254,6 @@ str: '', mru: new MRUCache(16) }; - - // Short-lived: content is valid only during one function call. These - // is to prevent repeated allocation/deallocation overheads -- the - // constructors/destructors of javascript Set/Map is assumed to be costlier - // than just calling clear() on these. - this.$specificSet = new Set(); - this.$exceptionSet = new Set(); - this.$proceduralSet = new Set(); - this.$dummySet = new Set(); - this.reset(); }; @@ -428,7 +419,7 @@ // hostnames). No distinction is made between declarative and // procedural selectors, since they really exist only to cancel // out other cosmetic filters. - writer.push([ 8, '', 0b001, compiled ]); + writer.push([ 8, '', `-${compiled}` ]); }; /******************************************************************************/ @@ -451,23 +442,8 @@ } writer.select('COSMETIC_FILTERS:SPECIFIC'); - - // https://github.com/chrisaljoudi/uBlock/issues/145 - let unhide = exception ? 1 : 0; - if ( not ) { unhide ^= 1; } - - let kind = 0; - if ( unhide === 1 ) { - kind |= 0b001; // Exception - } - if ( compiled.charCodeAt(0) === 0x7B /* '{' */ ) { - kind |= 0b010; // Procedural - } - if ( hostname === '*' ) { - kind |= 0b100; // Applies everywhere - } - - writer.push([ 8, hostname, kind, compiled ]); + const prefix = ((exception ? 1 : 0) ^ (not ? 1 : 0)) ? '-' : '+'; + writer.push([ 8, hostname, `${prefix}${compiled}` ]); }; /******************************************************************************/ @@ -498,17 +474,21 @@ // Handle specific filters meant to apply everywhere, i.e. selectors // not to be injected conditionally through the DOM surveyor. // hash, *, .promoted-tweet - case 8: - if ( args[2] === 0b100 ) { - if ( this.reSimpleHighGeneric.test(args[3]) ) - this.highlyGeneric.simple.dict.add(args[3]); - else { - this.highlyGeneric.complex.dict.add(args[3]); + case 8: { + if ( args[1] === '*' && args[2].charCodeAt(0) === 0x2D /* + */ ) { + const selector = args[2].slice(1); + if ( selector.charCodeAt(0) !== 0x7B /* { */ ) { + if ( this.reSimpleHighGeneric.test(selector) ) { + this.highlyGeneric.simple.dict.add(selector); + } else { + this.highlyGeneric.complex.dict.add(selector); + } + break; } - break; } - this.specificFilters.store(args[1], args[2] & 0b011, args[3]); + this.specificFilters.store(args[1], args[2]); break; + } default: this.discardedCount += 1; break; @@ -589,9 +569,7 @@ CosmeticFilteringEngine.prototype.fromSelfie = function(selfie) { if ( selfie.version !== this.selfieVersion ) { - throw new Error( - `cosmeticFilteringEngine: mismatched selfie version, ${selfie.version}, expected ${this.selfieVersion}` - ); + throw new TypeError('Bad selfie'); } this.acceptedCount = selfie.acceptedCount; this.discardedCount = selfie.discardedCount; @@ -629,16 +607,11 @@ type = undefined ) { const targetHostnameLength = targetHostname.length; - for ( let entry of this.selectorCache ) { - let hostname = entry[0]; - let item = entry[1]; + for ( const [ hostname, item ] of this.selectorCache ) { if ( targetHostname !== '*' ) { if ( hostname.endsWith(targetHostname) === false ) { continue; } - if ( - hostname.length !== targetHostnameLength && - hostname.charAt(hostname.length - targetHostnameLength - 1) !== '.' - ) { - continue; + if ( hostname.length !== targetHostnameLength ) { + if ( hostname.at(-1) !== '.' ) { continue; } } } item.remove(type); @@ -790,12 +763,8 @@ options.noSpecificCosmeticFiltering !== true || options.noGenericCosmeticFiltering !== true ) { - const specificSet = this.$specificSet; - const proceduralSet = this.$proceduralSet; - const exceptionSet = this.$exceptionSet; - const dummySet = this.$dummySet; - // Cached cosmetic filters: these are always declarative. + const specificSet = new Set(); if ( cacheEntry !== undefined ) { cacheEntry.retrieveCosmetic(specificSet, out.genericCosmeticHashes = []); if ( cacheEntry.disableSurveyor ) { @@ -803,34 +772,30 @@ } } + const allSet = new Set(); // Retrieve filters with a non-empty hostname - const retrieveSets = [ specificSet, exceptionSet, proceduralSet, exceptionSet ]; - const discardSets = [ dummySet, exceptionSet ]; - this.specificFilters.retrieve( - hostname, - options.noSpecificCosmeticFiltering ? discardSets : retrieveSets, - 1 - ); - // Retrieve filters with a regex-based hostname value - this.specificFilters.retrieve( - hostname, - options.noSpecificCosmeticFiltering ? discardSets : retrieveSets, - 3 - ); + this.specificFilters.retrieveSpecifics(allSet, hostname); // Retrieve filters with a entity-based hostname value - if ( request.entity !== '' ) { - this.specificFilters.retrieve( - `${hostname.slice(0, -request.domain.length)}${request.entity}`, - options.noSpecificCosmeticFiltering ? discardSets : retrieveSets, - 1 - ); - } + const entity = entityFromHostname(hostname, request.domain); + this.specificFilters.retrieveSpecifics(allSet, entity); + // Retrieve filters with a regex-based hostname value + this.specificFilters.retrieveSpecificsByRegex(allSet, hostname, request.url); // Retrieve filters with an empty hostname - this.specificFilters.retrieve( - hostname, - options.noGenericCosmeticFiltering ? discardSets : retrieveSets, - 2 - ); + this.specificFilters.retrieveGenerics(allSet); + + // Split filters in different groups + const proceduralSet = new Set(); + const exceptionSet = new Set(); + for ( const s of allSet ) { + const selector = s.slice(1); + if ( s.charCodeAt(0) === 0x2D /* - */ ) { + exceptionSet.add(selector); + } else if ( selector.charCodeAt(0) === 0x7B /* { */ ) { + proceduralSet.add(selector); + } else { + specificSet.add(selector); + } + } // Apply exceptions to specific filterset if ( exceptionSet.size !== 0 ) { @@ -853,12 +818,12 @@ // filters, so we extract and inject them immediately. if ( proceduralSet.size !== 0 ) { for ( const json of proceduralSet ) { - const pfilter = JSON.parse(json); if ( exceptionSet.has(json) ) { proceduralSet.delete(json); out.exceptedFilters.push(json); continue; } + const pfilter = JSON.parse(json); if ( exceptionSet.has(pfilter.raw) ) { proceduralSet.delete(json); out.exceptedFilters.push(pfilter.raw); @@ -912,12 +877,6 @@ } } } - - // Important: always clear used registers before leaving. - specificSet.clear(); - proceduralSet.clear(); - exceptionSet.clear(); - dummySet.clear(); } const details = { diff -Nru ublock-origin-1.62.0+dfsg/src/js/dashboard-common.js ublock-origin-1.67.0+dfsg/src/js/dashboard-common.js --- ublock-origin-1.62.0+dfsg/src/js/dashboard-common.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/dashboard-common.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - import { dom } from './dom.js'; /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/src/js/dashboard.js ublock-origin-1.67.0+dfsg/src/js/dashboard.js --- ublock-origin-1.62.0+dfsg/src/js/dashboard.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/dashboard.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - import { dom, qs$ } from './dom.js'; /******************************************************************************/ @@ -118,7 +116,7 @@ if ( iframe.src !== '' ) { iframe.src = ''; } - } catch(ex) { + } catch { } vAPI.defer.once(250).then(( ) => check()); }; diff -Nru ublock-origin-1.62.0+dfsg/src/js/devtools.js ublock-origin-1.67.0+dfsg/src/js/devtools.js --- ublock-origin-1.62.0+dfsg/src/js/devtools.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/devtools.js 2025-10-25 19:32:51.000000000 +0000 @@ -331,6 +331,7 @@ const fields = line.slice(5).split(/\s+/); const query = {}; for ( const field of fields ) { + if ( field === '' ) { continue; } if ( /[/.]/.test(field) ) { if ( query.url === undefined ) { query.url = field; diff -Nru ublock-origin-1.62.0+dfsg/src/js/diff-updater.js ublock-origin-1.67.0+dfsg/src/js/diff-updater.js --- ublock-origin-1.62.0+dfsg/src/js/diff-updater.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/diff-updater.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,15 +19,13 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - // This module can be dynamically loaded or spun off as a worker. /******************************************************************************/ const patches = new Map(); const encoder = new TextEncoder(); -const reFileName = /([^\/]+?)(?:#.+)?$/; +const reFileName = /([^/]+?)(?:#.+)?$/; const EMPTYLINE = ''; /******************************************************************************/ @@ -50,8 +48,7 @@ const resolveURL = (path, url) => { try { return new URL(path, url); - } - catch(_) { + } catch { } }; @@ -184,10 +181,10 @@ } async function fetchPatchDetailsFromCDNs(assetDetails) { - const { patchPath, cdnURLs } = assetDetails; + const { patchPath, cdnURLs, patchURLs } = assetDetails; if ( Array.isArray(cdnURLs) === false ) { return null; } if ( cdnURLs.length === 0 ) { return null; } - for ( const cdnURL of suffleArray(cdnURLs) ) { + for ( const cdnURL of suffleArray(patchURLs || cdnURLs) ) { const patchURL = resolveURL(patchPath, cdnURL); if ( patchURL === undefined ) { continue; } const response = await fetch(patchURL).catch(reason => { @@ -268,21 +265,21 @@ /******************************************************************************/ -const bc = new globalThis.BroadcastChannel('diffUpdater'); +const self = globalThis; -bc.onmessage = ev => { +self.onmessage = ev => { const message = ev.data || {}; switch ( message.what ) { case 'update': fetchAndApplyAllPatches(message).then(response => { - bc.postMessage(response); + self.postMessage(response); }).catch(error => { - bc.postMessage({ what: 'broken', error }); + self.postMessage({ what: 'broken', error }); }); break; } }; -bc.postMessage({ what: 'ready' }); +self.postMessage({ what: 'ready' }); /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/src/js/document-blocked.js ublock-origin-1.67.0+dfsg/src/js/document-blocked.js --- ublock-origin-1.62.0+dfsg/src/js/document-blocked.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/document-blocked.js 2025-10-25 19:32:51.000000000 +0000 @@ -21,60 +21,22 @@ import { dom, qs$ } from './dom.js'; import { i18n, i18n$ } from './i18n.js'; +import { faIconsInit } from './fa-icons.js'; /******************************************************************************/ const messaging = vAPI.messaging; -let details = {}; +const details = {}; { const matches = /details=([^&]+)/.exec(window.location.search); if ( matches !== null ) { - details = JSON.parse(decodeURIComponent(matches[1])); + Object.assign(details, JSON.parse(decodeURIComponent(matches[1]))); } } /******************************************************************************/ -(async ( ) => { - const response = await messaging.send('documentBlocked', { - what: 'listsFromNetFilter', - rawFilter: details.fs, - }); - if ( response instanceof Object === false ) { return; } - - let lists; - for ( const rawFilter in response ) { - if ( Object.prototype.hasOwnProperty.call(response, rawFilter) ) { - lists = response[rawFilter]; - break; - } - } - - if ( Array.isArray(lists) === false || lists.length === 0 ) { - qs$('#whyex').style.setProperty('visibility', 'collapse'); - return; - } - - const parent = qs$('#whyex > ul'); - parent.firstElementChild.remove(); // remove placeholder element - for ( const list of lists ) { - const listElem = dom.clone('#templates .filterList'); - const sourceElem = qs$(listElem, '.filterListSource'); - sourceElem.href += encodeURIComponent(list.assetKey); - sourceElem.append(i18n.patchUnicodeFlags(list.title)); - if ( typeof list.supportURL === 'string' && list.supportURL !== '' ) { - const supportElem = qs$(listElem, '.filterListSupport'); - dom.attr(supportElem, 'href', list.supportURL); - dom.cl.remove(supportElem, 'hidden'); - } - parent.appendChild(listElem); - } - qs$('#whyex').style.removeProperty('visibility'); -})(); - -/******************************************************************************/ - const urlToFragment = raw => { try { const fragment = new DocumentFragment(); @@ -85,7 +47,7 @@ b.append(hn); fragment.append(raw.slice(0,i), b, raw.slice(i+hn.length)); return fragment; - } catch(_) { + } catch { } return raw; }; @@ -94,7 +56,26 @@ dom.clear('#theURL > p > span:first-of-type'); qs$('#theURL > p > span:first-of-type').append(urlToFragment(details.url)); -dom.text('#why', details.fs); + +/******************************************************************************/ + +const lookupFilterLists = async ( ) => { + const response = await messaging.send('documentBlocked', { + what: 'listsFromNetFilter', + rawFilter: details.fs, + }); + if ( response instanceof Object === false ) { return; } + let lists; + for ( const rawFilter in response ) { + if ( Object.hasOwn(response, rawFilter) ) { + lists = response[rawFilter]; + break; + } + } + return lists; +}; + +/******************************************************************************/ if ( typeof details.to === 'string' && details.to.length !== 0 ) { const fragment = new DocumentFragment(); @@ -157,7 +138,7 @@ let url; try { url = new URL(rawURL); - } catch(ex) { + } catch { return false; } @@ -221,10 +202,6 @@ /******************************************************************************/ -const getTargetHostname = function() { - return details.hn; -}; - const proceedToURL = function() { window.location.replace(details.url); }; @@ -232,7 +209,7 @@ const proceedTemporary = async function() { await messaging.send('documentBlocked', { what: 'temporarilyWhitelistDocument', - hostname: getTargetHostname(), + hostname: details.hn, }); proceedToURL(); }; @@ -241,7 +218,7 @@ await messaging.send('documentBlocked', { what: 'toggleHostnameSwitch', name: 'no-strict-blocking', - hostname: getTargetHostname(), + hostname: details.hn, deep: true, state: true, persist: true, @@ -263,4 +240,49 @@ } }); +lookupFilterLists().then((lists = []) => { + let reason = details.reason; + if ( Boolean(reason) === false ) { + reason = lists.reduce((a, b) => a || b.reason, undefined); + } + if ( reason ) { + const msg = i18n$(`docblockedReason${reason.charAt(0).toUpperCase()}${reason.slice(1)}`); + if ( msg ) { reason = msg }; + } + const why = qs$(reason ? 'template.why-reason' : 'template.why') + .content + .cloneNode(true); + i18n.render(why); + dom.text(qs$(why, '.why'), details.fs); + if ( reason ) { + dom.text(qs$(why, 'summary'), `Reason: ${reason}`); + } + qs$('#why').append(why); + dom.cl.remove(dom.body, 'loading'); + + if ( lists.length === 0 ) { return; } + + const whyExtra = qs$('template.why-extra').content.cloneNode(true); + i18n.render(whyExtra); + + const listTemplate = qs$('template.filterList'); + const parent = qs$(whyExtra, '.why-extra'); + let separator = ''; + for ( const list of lists ) { + const listElem = listTemplate.content.cloneNode(true); + const sourceElem = qs$(listElem, '.filterListSource'); + sourceElem.href += encodeURIComponent(list.assetKey); + sourceElem.append(i18n.patchUnicodeFlags(list.title)); + if ( typeof list.supportURL === 'string' && list.supportURL !== '' ) { + const supportElem = qs$(listElem, '.filterListSupport'); + dom.attr(supportElem, 'href', list.supportURL); + dom.cl.remove(supportElem, 'hidden'); + } + parent.append(separator, listElem); + separator = '\u00A0\u2022\u00A0'; + } + faIconsInit(whyExtra); + qs$('#why .why').after(whyExtra); +}); + /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/src/js/dom-inspector.js ublock-origin-1.67.0+dfsg/src/js/dom-inspector.js --- ublock-origin-1.62.0+dfsg/src/js/dom-inspector.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/dom-inspector.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,9 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ /******************************************************************************/ const svgRoot = document.querySelector('svg'); @@ -36,20 +33,20 @@ const contentInspectorChannel = ev => { const msg = ev.data || {}; switch ( msg.what ) { - case 'quitInspector': { - shutdown(); - break; - } - case 'svgPaths': { - const paths = svgRoot.children; - paths[0].setAttribute('d', msg.paths[0]); - paths[1].setAttribute('d', msg.paths[1]); - paths[2].setAttribute('d', msg.paths[2]); - paths[3].setAttribute('d', msg.paths[3]); - break; - } - default: - break; + case 'quitInspector': { + shutdown(); + break; + } + case 'svgPaths': { + const paths = svgRoot.children; + paths[0].setAttribute('d', msg.paths[0]); + paths[1].setAttribute('d', msg.paths[1]); + paths[2].setAttribute('d', msg.paths[2]); + paths[3].setAttribute('d', msg.paths[3]); + break; + } + default: + break; } }; diff -Nru ublock-origin-1.62.0+dfsg/src/js/dom.js ublock-origin-1.67.0+dfsg/src/js/dom.js --- ublock-origin-1.62.0+dfsg/src/js/dom.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/dom.js 2025-10-25 19:32:51.000000000 +0000 @@ -156,6 +156,16 @@ elem.removeEventListener(type, callback, options); } } + + static onFirstShown(fn, elem) { + let observer = new IntersectionObserver(entries => { + if ( entries.every(a => a.isIntersecting === false) ) { return; } + try { fn(); } catch { } + observer.disconnect(); + observer = undefined; + }); + observer.observe(elem); + } } dom.cl = class { diff -Nru ublock-origin-1.62.0+dfsg/src/js/dyna-rules.js ublock-origin-1.67.0+dfsg/src/js/dyna-rules.js --- ublock-origin-1.62.0+dfsg/src/js/dyna-rules.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/dyna-rules.js 2025-10-25 19:32:51.000000000 +0000 @@ -21,15 +21,11 @@ /* global CodeMirror, diff_match_patch, uBlockDashboard */ -'use strict'; - -import publicSuffixList from '../lib/publicsuffixlist/publicsuffixlist.js'; - +import './codemirror/ubo-dynamic-filtering.js'; +import { dom, qs$, qsa$ } from './dom.js'; import { hostnameFromURI } from './uri-utils.js'; import { i18n$ } from './i18n.js'; -import { dom, qs$, qsa$ } from './dom.js'; - -import './codemirror/ubo-dynamic-filtering.js'; +import publicSuffixList from '../lib/publicsuffixlist/publicsuffixlist.js'; /******************************************************************************/ @@ -181,7 +177,7 @@ edit.startOperation(); for ( const key in thePanes ) { - if ( thePanes.hasOwnProperty(key) === false ) { continue; } + if ( Object.hasOwn(thePanes, key) === false ) { continue; } const doc = thePanes[key].doc; const rules = filterRules(key); if ( @@ -327,7 +323,7 @@ // https://github.com/chrisaljoudi/uBlock/issues/757 // Support RequestPolicy rule syntax let result = this.result; - let matches = /\[origins-to-destinations\]([^\[]+)/.exec(result); + let matches = /\[origins-to-destinations\]([^[]+)/.exec(result); if ( matches && matches.length === 2 ) { result = matches[1].trim() .replace(/\|/g, ' ') @@ -459,13 +455,12 @@ thePanes.orig.modified.join('\n'), thePanes.edit.modified.join('\n') ); - const ll = []; let il = 0, lellipsis = false; - const rr = []; let ir = 0, rellipsis = false; + const ll = []; let lellipsis = false; + const rr = []; let rellipsis = false; for ( let i = 0; i < diffs.length; i++ ) { const diff = diffs[i]; if ( diff[0] === 0 ) { lellipsis = rellipsis = true; - il += 1; ir += 1; continue; } if ( diff[0] < 0 ) { @@ -475,7 +470,6 @@ lellipsis = rellipsis = false; } ll.push(diff[1].trim()); - il += 1; continue; } /* diff[0] > 0 */ @@ -485,7 +479,6 @@ lellipsis = rellipsis = false; } rr.push(diff[1].trim()); - ir += 1; } if ( lellipsis ) { ll.push('...'); } if ( rellipsis ) { rr.push('...'); } diff -Nru ublock-origin-1.62.0+dfsg/src/js/dynamic-net-filtering.js ublock-origin-1.67.0+dfsg/src/js/dynamic-net-filtering.js --- ublock-origin-1.62.0+dfsg/src/js/dynamic-net-filtering.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/dynamic-net-filtering.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,24 +19,18 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - -import punycode from '../lib/punycode.js'; - -import { LineIterator } from './text-utils.js'; - import { decomposeHostname, domainFromHostname, } from './uri-utils.js'; +import { LineIterator } from './text-utils.js'; +import punycode from '../lib/punycode.js'; /******************************************************************************/ // Object.create(null) is used below to eliminate worries about unexpected // property names in prototype chain -- and this way we don't have to use -// hasOwnProperty() to avoid this. +// Object.hasOwn() to avoid this. const supportedDynamicTypes = Object.create(null); Object.assign(supportedDynamicTypes, { @@ -73,7 +67,7 @@ ]); // For performance purpose, as simple tests as possible -const reBadHostname = /[^0-9a-z_.\[\]:%-]/; +const reBadHostname = /[^0-9a-z_.[\]:%-]/; const reNotASCII = /[^\x20-\x7F]/; const decomposedSource = []; const decomposedDestination = []; diff -Nru ublock-origin-1.62.0+dfsg/src/js/epicker-ui.js ublock-origin-1.67.0+dfsg/src/js/epicker-ui.js --- ublock-origin-1.62.0+dfsg/src/js/epicker-ui.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/epicker-ui.js 2025-10-25 19:32:51.000000000 +0000 @@ -331,7 +331,7 @@ mx: ev.clientX, my: ev.clientY, options: { - stay: ev.shiftKey || ev.type === 'touch', + stay: true, highlight: ev.target !== svgIslands, }, }); @@ -822,6 +822,8 @@ unpausePicker(); + $id('quit').addEventListener('click', onQuitClicked); + if ( pickerRoot.classList.contains('zap') ) { return; } cmEditor.on('changes', onCandidateChanged); @@ -837,7 +839,6 @@ dom.cl.toggle(pickerRoot, 'minimized'); } }); - $id('quit').addEventListener('click', onQuitClicked); $id('move').addEventListener('mousedown', onStartMoving); $id('move').addEventListener('touchstart', onStartMoving); $id('candidateFilters').addEventListener('click', onCandidateClicked); diff -Nru ublock-origin-1.62.0+dfsg/src/js/fa-icons.js ublock-origin-1.67.0+dfsg/src/js/fa-icons.js --- ublock-origin-1.62.0+dfsg/src/js/fa-icons.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/fa-icons.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uMatrix */ -'use strict'; - /******************************************************************************/ export const faIconsInit = (( ) => { diff -Nru ublock-origin-1.62.0+dfsg/src/js/filtering-engines.js ublock-origin-1.67.0+dfsg/src/js/filtering-engines.js --- ublock-origin-1.62.0+dfsg/src/js/filtering-engines.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/filtering-engines.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,10 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - import DynamicHostRuleFiltering from './dynamic-net-filtering.js'; import DynamicSwitchRuleFiltering from './hnswitches.js'; import DynamicURLRuleFiltering from './url-net-filtering.js'; diff -Nru ublock-origin-1.62.0+dfsg/src/js/hnswitches.js ublock-origin-1.67.0+dfsg/src/js/hnswitches.js --- ublock-origin-1.62.0+dfsg/src/js/hnswitches.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/hnswitches.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,16 +19,9 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint bitwise: false */ - -'use strict'; - -/******************************************************************************/ - -import punycode from '../lib/punycode.js'; - -import { decomposeHostname } from './uri-utils.js'; import { LineIterator } from './text-utils.js'; +import { decomposeHostname } from './uri-utils.js'; +import punycode from '../lib/punycode.js'; /******************************************************************************/ @@ -36,7 +29,7 @@ // Object.create(null) is used below to eliminate worries about unexpected // property names in prototype chain -- and this way we don't have to use -// hasOwnProperty() to avoid this. +// Object.hasOwn() to avoid this. const switchBitOffsets = Object.create(null); Object.assign(switchBitOffsets, { diff -Nru ublock-origin-1.62.0+dfsg/src/js/hntrie.js ublock-origin-1.67.0+dfsg/src/js/hntrie.js --- ublock-origin-1.62.0+dfsg/src/js/hntrie.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/hntrie.js 2025-10-25 19:32:51.000000000 +0000 @@ -586,6 +586,7 @@ dumpInfo() { return [ `Buffer size (Uint8Array): ${this.buf32[CHAR1_SLOT].toLocaleString('en')}`, + ` Char segment size: ${(this.buf32[CHAR1_SLOT] - this.buf32[CHAR0_SLOT]).toLocaleString('en')}`, `WASM: ${this.wasmMemory === null ? 'disabled' : 'enabled'}`, ].join('\n'); } diff -Nru ublock-origin-1.62.0+dfsg/src/js/html-filtering.js ublock-origin-1.67.0+dfsg/src/js/html-filtering.js --- ublock-origin-1.62.0+dfsg/src/js/html-filtering.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/html-filtering.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,22 +19,18 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - +import { StaticExtFilteringHostnameDB } from './static-ext-filtering-db.js'; +import { entityFromHostname } from './uri-utils.js'; import logger from './logger.js'; -import µb from './background.js'; import { sessionFirewall } from './filtering-engines.js'; -import { StaticExtFilteringHostnameDB } from './static-ext-filtering-db.js'; -import { entityFromDomain } from './uri-utils.js'; +import µb from './background.js'; /******************************************************************************/ const pselectors = new Map(); const duplicates = new Set(); -const filterDB = new StaticExtFilteringHostnameDB(2); +const filterDB = new StaticExtFilteringHostnameDB(); let acceptedCount = 0; let discardedCount = 0; @@ -264,7 +260,7 @@ .setDocOriginFromURL(details.url) .setFilter({ source: 'extended', - raw: `${exception === 0 ? '##' : '#@#'}^${selector}` + raw: `${exception === 0 ? '##' : '#@#'}^${selector}`, }) .toLogger(); } @@ -342,16 +338,11 @@ let hasOnlyNegated = true; for ( const { hn, not, bad } of parser.getExtFilterDomainIterator() ) { if ( bad ) { continue; } - let kind = isException ? 0b01 : 0b00; - if ( not ) { - kind ^= 0b01; - } else { + const prefix = ((isException ? 1 : 0) ^ (not ? 1 : 0)) ? '-' : '+'; + if ( not === false ) { hasOnlyNegated = false; } - if ( compiled.charCodeAt(0) === 0x7B /* '{' */ ) { - kind |= 0b10; - } - compiledFilters.push([ 64, hn, kind, compiled ]); + compiledFilters.push([ 64, hn, `${prefix}${compiled}` ]); } // Not allowed since it's equivalent to forbidden generic HTML filters @@ -377,59 +368,45 @@ } duplicates.add(fingerprint); const args = reader.args(); - filterDB.store(args[1], args[2], args[3]); + filterDB.store(args[1], args[2]); } }; htmlFilteringEngine.retrieve = function(fctxt) { - const plains = new Set(); - const procedurals = new Set(); - const exceptions = new Set(); - const retrieveSets = [ plains, exceptions, procedurals, exceptions ]; - + const all = new Set(); const hostname = fctxt.getHostname(); - filterDB.retrieve(hostname, retrieveSets); - - const domain = fctxt.getDomain(); - const entity = entityFromDomain(domain); - const hostnameEntity = entity !== '' - ? `${hostname.slice(0, -domain.length)}${entity}` - : '*'; - filterDB.retrieve(hostnameEntity, retrieveSets, 1); - - if ( plains.size === 0 && procedurals.size === 0 ) { return; } + filterDB.retrieveSpecifics(all, hostname); + const entity = entityFromHostname(hostname, fctxt.getDomain()); + filterDB.retrieveSpecifics(all, entity); + filterDB.retrieveSpecificsByRegex(all, hostname, fctxt.url); + filterDB.retrieveGenerics(all); + if ( all.size === 0 ) { return; } // https://github.com/gorhill/uBlock/issues/2835 // Do not filter if the site is under an `allow` rule. - if ( - µb.userSettings.advancedUserEnabled && - sessionFirewall.evaluateCellZY(hostname, hostname, '*') === 2 - ) { - return; + if ( µb.userSettings.advancedUserEnabled ) { + if ( sessionFirewall.evaluateCellZY(hostname, hostname, '*') === 2 ) { return; } } - const out = { plains, procedurals }; - - if ( exceptions.size === 0 ) { - return out; - } - - for ( const selector of exceptions ) { - if ( plains.has(selector) ) { - plains.delete(selector); - logOne(fctxt, 1, selector); - continue; - } - if ( procedurals.has(selector) ) { - procedurals.delete(selector); - logOne(fctxt, 1, JSON.parse(selector).raw); - continue; + // Split filters in different groups + const plains = new Set(); + const procedurals = new Set(); + for ( const s of all ) { + if ( s.charCodeAt(0) === 0x2D /* - */ ) { continue; } + const selector = s.slice(1); + const isProcedural = selector.startsWith('{'); + if ( all.has(`-${selector}`) ) { + logOne(fctxt, 1, isProcedural ? JSON.parse(selector).raw : selector); + } else if ( isProcedural ) { + procedurals.add(selector); + } else { + plains.add(selector); } } - if ( plains.size !== 0 || procedurals.size !== 0 ) { - return out; - } + if ( plains.size === 0 && procedurals.size === 0 ) { return; } + + return { plains, procedurals }; }; htmlFilteringEngine.apply = function(doc, details, selectors) { diff -Nru ublock-origin-1.62.0+dfsg/src/js/httpheader-filtering.js ublock-origin-1.67.0+dfsg/src/js/httpheader-filtering.js --- ublock-origin-1.62.0+dfsg/src/js/httpheader-filtering.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/httpheader-filtering.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,24 +19,16 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - +import { StaticExtFilteringHostnameDB } from './static-ext-filtering-db.js'; +import { entityFromHostname } from './uri-utils.js'; import logger from './logger.js'; -import µb from './background.js'; -import { entityFromDomain } from './uri-utils.js'; import { sessionFirewall } from './filtering-engines.js'; -import { StaticExtFilteringHostnameDB } from './static-ext-filtering-db.js'; -import * as sfp from './static-filtering-parser.js'; +import µb from './background.js'; /******************************************************************************/ const duplicates = new Set(); -const filterDB = new StaticExtFilteringHostnameDB(1); - -const $headers = new Set(); -const $exceptions = new Set(); +const filterDB = new StaticExtFilteringHostnameDB(); let acceptedCount = 0; let discardedCount = 0; @@ -57,7 +49,7 @@ modifier: true, result: isException ? 2 : 1, source: 'extended', - raw: `${(isException ? '#@#' : '##')}^responseheader(${token})` + raw: `${(isException ? '#@#' : '##')}^responseheader(${token})`, }) .toLogger(); }; @@ -87,8 +79,7 @@ writer.select('HTTPHEADER_FILTERS'); const isException = parser.isException(); - const root = parser.getBranchFromType(sfp.NODE_TYPE_EXT_PATTERN_RESPONSEHEADER); - const headerName = parser.getNodeString(root); + const headerName = parser.getResponseheaderName(); // Tokenless is meaningful only for exception filters. if ( headerName === '' && isException === false ) { return; } @@ -107,14 +98,8 @@ for ( const { hn, not, bad } of parser.getExtFilterDomainIterator() ) { if ( bad ) { continue; } - let kind = 0; - if ( isException ) { - if ( not ) { continue; } - kind |= 1; - } else if ( not ) { - kind |= 1; - } - writer.push([ 64, hn, kind, headerName ]); + const prefix = ((isException ? 1 : 0) ^ (not ? 1 : 0)) ? '-' : '+'; + writer.push([ 64, hn, `${prefix}${headerName}` ]); } }; @@ -135,8 +120,7 @@ } duplicates.add(fingerprint); const args = reader.args(); - if ( args.length < 4 ) { continue; } - filterDB.store(args[1], args[2], args[3]); + filterDB.store(args[1], args[2]); } }; @@ -146,37 +130,39 @@ const hostname = fctxt.getHostname(); if ( hostname === '' ) { return; } - const domain = fctxt.getDomain(); - let entity = entityFromDomain(domain); - if ( entity !== '' ) { - entity = `${hostname.slice(0, -domain.length)}${entity}`; - } else { - entity = '*'; - } - - $headers.clear(); - $exceptions.clear(); - - filterDB.retrieve(hostname, [ $headers, $exceptions ]); - filterDB.retrieve(entity, [ $headers, $exceptions ], 1); - if ( $headers.size === 0 ) { return; } + const all = new Set(); + filterDB.retrieveSpecifics(all, hostname); + const entity = entityFromHostname(hostname, fctxt.getDomain()); + filterDB.retrieveSpecifics(all, entity); + filterDB.retrieveSpecificsByRegex(all, hostname, fctxt.url); + filterDB.retrieveGenerics(all); + if ( all.size === 0 ) { return; } // https://github.com/gorhill/uBlock/issues/2835 // Do not filter response headers if the site is under an `allow` rule. - if ( - µb.userSettings.advancedUserEnabled && - sessionFirewall.evaluateCellZY(hostname, hostname, '*') === 2 - ) { - return; + if ( µb.userSettings.advancedUserEnabled ) { + if ( sessionFirewall.evaluateCellZY(hostname, hostname, '*') === 2 ) { return; } + } + + // Split filters in different groups + const filters = new Set(); + const exceptions = new Set(); + for ( const s of all ) { + const selector = s.slice(1); + if ( s.charCodeAt(0) === 0x2D /* - */ ) { + exceptions.add(selector); + } else { + filters.add(selector); + } } - const hasGlobalException = $exceptions.has(''); + const hasGlobalException = exceptions.has(''); let modified = false; let i = 0; - for ( const name of $headers ) { - const isExcepted = hasGlobalException || $exceptions.has(name); + for ( const name of filters ) { + const isExcepted = hasGlobalException || exceptions.has(name); if ( isExcepted ) { if ( logger.enabled ) { logOne(true, hasGlobalException ? '' : name, fctxt); diff -Nru ublock-origin-1.62.0+dfsg/src/js/i18n.js ublock-origin-1.67.0+dfsg/src/js/i18n.js --- ublock-origin-1.62.0+dfsg/src/js/i18n.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/i18n.js 2025-10-25 19:32:51.000000000 +0000 @@ -173,7 +173,7 @@ } textout += textin.slice(0, match.index); let prop = match[0].slice(2, -2); - if ( Object.prototype.hasOwnProperty.call(dict, prop) ) { + if ( Object.hasOwn(dict, prop) ) { textout += dict[prop].replace(//g, '>'); } else { @@ -263,6 +263,11 @@ elem.setAttribute('aria-label', text); } } + + for ( const elem of root.querySelectorAll('[data-i18n-label]') ) { + const text = i18n$(elem.getAttribute('data-i18n-label')); + elem.setAttribute('label', text); + } }; i18n.renderElapsedTimeToString = function(tstamp) { diff -Nru ublock-origin-1.62.0+dfsg/src/js/jsonpath.js ublock-origin-1.67.0+dfsg/src/js/jsonpath.js --- ublock-origin-1.62.0+dfsg/src/js/jsonpath.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/jsonpath.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,524 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock + +*/ + +/** + * Implement the parsing of uBO-flavored JSON path queries. + * + * Reference to original JSON path syntax: + * https://goessner.net/articles/JsonPath/index.html + * + * uBO-flavored JSON path implementation differs as follow: + * + * - Both $ and @ are implicit. Though you can use them, you do not have to. + * Use $ only when the implicit context is not that of root. Example: + * - Official: $..book[?(@.isbn)] + * - uBO-flavored: ..book[?(.isbn)] + * + * - uBO-flavor syntax does not (yet) support: + * - Array slice operator + * + * - Regarding filter expressions, uBO-flavored JSON path supports a limited + * set of expressions since unlike the official implementation, uBO can't use + * JS eval() to evaluate arbitrary JS expressions. The operand MUST be valid + * JSON. The currently supported expressions are: + * - ==: strict equality + * - !=: strict inequality + * - <: less than + * - <=: less than or equal to + * - >: greater than + * - >=: greater than or equal to + * - ^=: stringified value starts with + * - $=: stringified value ends with + * - *=: stringified value includes + * - =/.../: regular expression matches + * + * - Examples (from "JSONPath examples" at reference link) + * - .store.book[*].author + * - ..author + * - .store.* + * - .store..price + * - ..book[2] + * - ..book[?(.isbn)] + * - ..book[?(.price<10)] + * - ..* + * + * uBO-flavored syntax supports assigning a value to a resolved JSON path by + * appending `=[value]` to the JSON path query. The assigned value MUST be + * valid JSON. Examples: + * - .store..price=0 + * - .store.book[*].author="redacted" + * + * A JSONPath instance can be use to compile a JSON path query, and the result + * of the compilation can be applied to different objects. When a JSON path + * query does not assign a value, the resolved property will be removed. + * + * More capabilities can be added in the future as needed. + * + * */ + +export class JSONPath { + static create(query) { + const jsonp = new JSONPath(); + jsonp.compile(query); + return jsonp; + } + static toJSON(obj, stringifier, ...args) { + return (stringifier || JSON.stringify)(obj, ...args) + .replace(/\//g, '\\/'); + } + get value() { + return this.#compiled && this.#compiled.rval; + } + set value(v) { + if ( this.#compiled === undefined ) { return; } + this.#compiled.rval = v; + } + get valid() { + return this.#compiled !== undefined; + } + compile(query) { + this.#compiled = undefined; + const r = this.#compile(query, 0); + if ( r === undefined ) { return; } + if ( r.i !== query.length ) { + let val; + if ( query.startsWith('=', r.i) ) { + if ( /^=repl\(.+\)$/.test(query.slice(r.i)) ) { + r.modify = 'repl'; + val = query.slice(r.i+6, -1); + } else { + val = query.slice(r.i+1); + } + } else if ( query.startsWith('+=', r.i) ) { + r.modify = '+'; + val = query.slice(r.i+2); + } + try { r.rval = JSON.parse(val); } + catch { return; } + } + this.#compiled = r; + } + evaluate(root) { + if ( this.valid === false ) { return []; } + this.#root = root; + const paths = this.#evaluate(this.#compiled.steps, []); + this.#root = null; + return paths; + } + apply(root) { + if ( this.valid === false ) { return; } + const { rval } = this.#compiled; + this.#root = { '$': root }; + const paths = this.#evaluate(this.#compiled.steps, []); + let i = paths.length + if ( i === 0 ) { this.#root = null; return; } + while ( i-- ) { + const { obj, key } = this.#resolvePath(paths[i]); + if ( rval !== undefined ) { + this.#modifyVal(obj, key); + } else if ( Array.isArray(obj) && typeof key === 'number' ) { + obj.splice(key, 1); + } else { + delete obj[key]; + } + } + const result = this.#root['$'] ?? null; + this.#root = null; + return result; + } + dump() { + return JSON.stringify(this.#compiled); + } + toJSON(obj, ...args) { + return JSONPath.toJSON(obj, null, ...args) + } + get [Symbol.toStringTag]() { + return 'JSONPath'; + } + #UNDEFINED = 0; + #ROOT = 1; + #CURRENT = 2; + #CHILDREN = 3; + #DESCENDANTS = 4; + #reUnquotedIdentifier = /^[A-Za-z_][\w]*|^\*/; + #reExpr = /^([!=^$*]=|[<>]=?)(.+?)\]/; + #reIndice = /^-?\d+/; + #root; + #compiled; + #compile(query, i) { + if ( query.length === 0 ) { return; } + const steps = []; + let c = query.charCodeAt(i); + if ( c === 0x24 /* $ */ ) { + steps.push({ mv: this.#ROOT }); + i += 1; + } else if ( c === 0x40 /* @ */ ) { + steps.push({ mv: this.#CURRENT }); + i += 1; + } else { + steps.push({ mv: i === 0 ? this.#ROOT : this.#CURRENT }); + } + let mv = this.#UNDEFINED; + for (;;) { + if ( i === query.length ) { break; } + c = query.charCodeAt(i); + if ( c === 0x20 /* whitespace */ ) { + i += 1; + continue; + } + // Dot accessor syntax + if ( c === 0x2E /* . */ ) { + if ( mv !== this.#UNDEFINED ) { return; } + if ( query.startsWith('..', i) ) { + mv = this.#DESCENDANTS; + i += 2; + } else { + mv = this.#CHILDREN; + i += 1; + } + continue; + } + if ( c !== 0x5B /* [ */ ) { + if ( mv === this.#UNDEFINED ) { + const step = steps.at(-1); + if ( step === undefined ) { return; } + i = this.#compileExpr(query, step, i); + break; + } + const s = this.#consumeUnquotedIdentifier(query, i); + if ( s === undefined ) { return; } + steps.push({ mv, k: s }); + i += s.length; + mv = this.#UNDEFINED; + continue; + } + // Bracket accessor syntax + if ( query.startsWith('[?', i) ) { + const not = query.charCodeAt(i+2) === 0x21 /* ! */; + const j = i + 2 + (not ? 1 : 0); + const r = this.#compile(query, j); + if ( r === undefined ) { return; } + if ( query.startsWith(']', r.i) === false ) { return; } + if ( not ) { r.steps.at(-1).not = true; } + steps.push({ mv: mv || this.#CHILDREN, steps: r.steps }); + i = r.i + 1; + mv = this.#UNDEFINED; + continue; + } + if ( query.startsWith('[*]', i) ) { + mv ||= this.#CHILDREN; + steps.push({ mv, k: '*' }); + i += 3; + mv = this.#UNDEFINED; + continue; + } + const r = this.#consumeIdentifier(query, i+1); + if ( r === undefined ) { return; } + mv ||= this.#CHILDREN; + steps.push({ mv, k: r.s }); + i = r.i + 1; + mv = this.#UNDEFINED; + } + if ( steps.length === 0 ) { return; } + if ( mv !== this.#UNDEFINED ) { return; } + return { steps, i }; + } + #evaluate(steps, pathin) { + let resultset = []; + if ( Array.isArray(steps) === false ) { return resultset; } + for ( const step of steps ) { + switch ( step.mv ) { + case this.#ROOT: + resultset = [ [ '$' ] ]; + break; + case this.#CURRENT: + resultset = [ pathin ]; + break; + case this.#CHILDREN: + case this.#DESCENDANTS: + resultset = this.#getMatches(resultset, step); + break; + default: + break; + } + } + return resultset; + } + #getMatches(listin, step) { + const listout = []; + for ( const pathin of listin ) { + const { value: owner } = this.#resolvePath(pathin); + if ( step.k === '*' ) { + this.#getMatchesFromAll(pathin, step, owner, listout); + } else if ( step.k !== undefined ) { + this.#getMatchesFromKeys(pathin, step, owner, listout); + } else if ( step.steps ) { + this.#getMatchesFromExpr(pathin, step, owner, listout); + } + } + return listout; + } + #getMatchesFromAll(pathin, step, owner, out) { + const recursive = step.mv === this.#DESCENDANTS; + for ( const { path } of this.#getDescendants(owner, recursive) ) { + out.push([ ...pathin, ...path ]); + } + } + #getMatchesFromKeys(pathin, step, owner, out) { + const kk = Array.isArray(step.k) ? step.k : [ step.k ]; + for ( const k of kk ) { + const normalized = this.#evaluateExpr(step, owner, k); + if ( normalized === undefined ) { continue; } + out.push([ ...pathin, normalized ]); + } + if ( step.mv !== this.#DESCENDANTS ) { return; } + for ( const { obj, key, path } of this.#getDescendants(owner, true) ) { + for ( const k of kk ) { + const normalized = this.#evaluateExpr(step, obj[key], k); + if ( normalized === undefined ) { continue; } + out.push([ ...pathin, ...path, normalized ]); + } + } + } + #getMatchesFromExpr(pathin, step, owner, out) { + const recursive = step.mv === this.#DESCENDANTS; + if ( Array.isArray(owner) === false ) { + const r = this.#evaluate(step.steps, pathin); + if ( r.length !== 0 ) { out.push(pathin); } + if ( recursive !== true ) { return; } + } + for ( const { obj, key, path } of this.#getDescendants(owner, recursive) ) { + if ( Array.isArray(obj[key]) ) { continue; } + const q = [ ...pathin, ...path ]; + const r = this.#evaluate(step.steps, q); + if ( r.length === 0 ) { continue; } + out.push(q); + } + } + #normalizeKey(owner, key) { + if ( typeof key === 'number' ) { + if ( Array.isArray(owner) ) { + return key >= 0 ? key : owner.length + key; + } + } + return key; + } + #getDescendants(v, recursive) { + const iterator = { + next() { + const n = this.stack.length; + if ( n === 0 ) { + this.value = undefined; + this.done = true; + return this; + } + const details = this.stack[n-1]; + const entry = details.keys.next(); + if ( entry.done ) { + this.stack.pop(); + this.path.pop(); + return this.next(); + } + this.path[n-1] = entry.value; + this.value = { + obj: details.obj, + key: entry.value, + path: this.path.slice(), + }; + const v = this.value.obj[this.value.key]; + if ( recursive ) { + if ( Array.isArray(v) ) { + this.stack.push({ obj: v, keys: v.keys() }); + } else if ( typeof v === 'object' && v !== null ) { + this.stack.push({ obj: v, keys: Object.keys(v).values() }); + } + } + return this; + }, + path: [], + value: undefined, + done: false, + stack: [], + [Symbol.iterator]() { return this; }, + }; + if ( Array.isArray(v) ) { + iterator.stack.push({ obj: v, keys: v.keys() }); + } else if ( typeof v === 'object' && v !== null ) { + iterator.stack.push({ obj: v, keys: Object.keys(v).values() }); + } + return iterator; + } + #consumeIdentifier(query, i) { + const keys = []; + for (;;) { + const c0 = query.charCodeAt(i); + if ( c0 === 0x5D /* ] */ ) { break; } + if ( c0 === 0x2C /* , */ ) { + i += 1; + continue; + } + if ( c0 === 0x27 /* ' */ ) { + const r = this.#untilChar(query, 0x27 /* ' */, i+1) + if ( r === undefined ) { return; } + keys.push(r.s); + i = r.i; + continue; + } + if ( c0 === 0x2D /* - */ || c0 >= 0x30 && c0 <= 0x39 ) { + const match = this.#reIndice.exec(query.slice(i)); + if ( match === null ) { return; } + const indice = parseInt(query.slice(i), 10); + keys.push(indice); + i += match[0].length; + continue; + } + const s = this.#consumeUnquotedIdentifier(query, i); + if ( s === undefined ) { return; } + keys.push(s); + i += s.length; + } + return { s: keys.length === 1 ? keys[0] : keys, i }; + } + #consumeUnquotedIdentifier(query, i) { + const match = this.#reUnquotedIdentifier.exec(query.slice(i)); + if ( match === null ) { return; } + return match[0]; + } + #untilChar(query, targetCharCode, i) { + const len = query.length; + const parts = []; + let beg = i, end = i; + for (;;) { + if ( end === len ) { return; } + const c = query.charCodeAt(end); + if ( c === targetCharCode ) { + parts.push(query.slice(beg, end)); + end += 1; + break; + } + if ( c === 0x5C /* \ */ && (end+1) < len ) { + parts.push(query.slice(beg, end)); + const d = query.charCodeAt(end+1); + if ( d === targetCharCode || d === 0x5C ) { + end += 1; + beg = end; + } + } + end += 1; + } + return { s: parts.join(''), i: end }; + } + #compileExpr(query, step, i) { + if ( query.startsWith('=/', i) ) { + const r = this.#untilChar(query, 0x2F /* / */, i+2); + if ( r === undefined ) { return i; } + const match = /^[i]/.exec(query.slice(r.i)); + try { + step.rval = new RegExp(r.s, match && match[0] || undefined); + } catch { + return i; + } + step.op = 're'; + if ( match ) { r.i += match[0].length; } + return r.i; + } + const match = this.#reExpr.exec(query.slice(i)); + if ( match === null ) { return i; } + try { + step.rval = JSON.parse(match[2]); + step.op = match[1]; + } catch { + } + return i + match[1].length + match[2].length; + } + #resolvePath(path) { + if ( path.length === 0 ) { return { value: this.#root }; } + const key = path.at(-1); + let obj = this.#root + for ( let i = 0, n = path.length-1; i < n; i++ ) { + obj = obj[path[i]]; + } + return { obj, key, value: obj[key] }; + } + #evaluateExpr(step, owner, key) { + if ( owner === undefined || owner === null ) { return; } + if ( typeof key === 'number' ) { + if ( Array.isArray(owner) === false ) { return; } + } + const k = this.#normalizeKey(owner, key); + const hasOwn = Object.hasOwn(owner, k); + if ( step.op !== undefined && hasOwn === false ) { return; } + const target = step.not !== true; + const v = owner[k]; + let outcome = false; + switch ( step.op ) { + case '==': outcome = (v === step.rval) === target; break; + case '!=': outcome = (v !== step.rval) === target; break; + case '<': outcome = (v < step.rval) === target; break; + case '<=': outcome = (v <= step.rval) === target; break; + case '>': outcome = (v > step.rval) === target; break; + case '>=': outcome = (v >= step.rval) === target; break; + case '^=': outcome = `${v}`.startsWith(step.rval) === target; break; + case '$=': outcome = `${v}`.endsWith(step.rval) === target; break; + case '*=': outcome = `${v}`.includes(step.rval) === target; break; + case 're': outcome = step.rval.test(`${v}`); break; + default: outcome = hasOwn === target; break; + } + if ( outcome ) { return k; } + } + #modifyVal(obj, key) { + const { modify, rval } = this.#compiled; + switch ( modify ) { + case undefined: + obj[key] = rval; + break; + case '+': { + if ( rval instanceof Object === false ) { return; } + const lval = obj[key]; + if ( lval instanceof Object === false ) { return; } + if ( Array.isArray(lval) ) { return; } + for ( const [ k, v ] of Object.entries(rval) ) { + lval[k] = v; + } + break; + } + case 'repl': { + const lval = obj[key]; + if ( typeof lval !== 'string' ) { return; } + if ( this.#compiled.re === undefined ) { + this.#compiled.re = null; + try { + this.#compiled.re = rval.regex !== undefined + ? new RegExp(rval.regex, rval.flags) + : new RegExp(rval.pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')); + } catch { + } + } + if ( this.#compiled.re === null ) { return; } + obj[key] = lval.replace(this.#compiled.re, rval.replacement); + break; + } + default: + break; + } + } +} diff -Nru ublock-origin-1.62.0+dfsg/src/js/logger-ui-inspector.js ublock-origin-1.67.0+dfsg/src/js/logger-ui-inspector.js --- ublock-origin-1.62.0+dfsg/src/js/logger-ui-inspector.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/logger-ui-inspector.js 2025-10-25 19:32:51.000000000 +0000 @@ -88,7 +88,7 @@ toContentPort = browser.tabs.connect(tabId, { frameId }); toContentPort.onMessage.addListener(onContentMessage); toContentPort.onDisconnect.addListener(onContentDisconnect); - } catch(_) { + } catch { } }; diff -Nru ublock-origin-1.62.0+dfsg/src/js/logger-ui.js ublock-origin-1.67.0+dfsg/src/js/logger-ui.js --- ublock-origin-1.62.0+dfsg/src/js/logger-ui.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/logger-ui.js 2025-10-25 19:32:51.000000000 +0000 @@ -70,9 +70,6 @@ return isNaN(tabId) ? 0 : tabId; }; -const hasOwnProperty = (o, p) => - Object.prototype.hasOwnProperty.call(o, p); - const dispatchTabidChange = vAPI.defer.create(( ) => { document.dispatchEvent(new Event('tabIdChanged')); }); @@ -253,7 +250,7 @@ this.voided = false; if ( details instanceof Object === false ) { return; } for ( const prop in this ) { - if ( hasOwnProperty(details, prop) === false ) { continue; } + if ( Object.hasOwn(details, prop) === false ) { continue; } this[prop] = details[prop]; } if ( details.aliasURL !== undefined ) { @@ -1224,7 +1221,7 @@ const onColorsReady = function(response) { dom.cl.toggle(dom.body, 'dirty', response.dirty); for ( const url in response.colors ) { - if ( hasOwnProperty(response.colors, url) === false ) { continue; } + if ( Object.hasOwn(response.colors, url) === false ) { continue; } const colorEntry = response.colors[url]; const node = qs$(dialog, `.dynamic .entry .action[data-url="${url}"]`); if ( node === null ) { continue; } @@ -1291,7 +1288,7 @@ dom.cl.toggle( qs$(dialog, '#createStaticFilter'), 'disabled', - hasOwnProperty(createdStaticFilters, value) || value === '' + Object.hasOwn(createdStaticFilters, value) || value === '' ); }; @@ -1332,7 +1329,7 @@ const value = staticFilterNode().value .replace(/^((?:@@)?\/.+\/)(\$|$)/, '$1*$2'); // Avoid duplicates - if ( hasOwnProperty(createdStaticFilters, value) ) { return; } + if ( Object.hasOwn(createdStaticFilters, value) ) { return; } createdStaticFilters[value] = true; // https://github.com/uBlockOrigin/uBlock-issues/issues/1281#issuecomment-704217175 // TODO: @@ -1595,9 +1592,8 @@ } let bestMatchFilter = ''; for ( const filter in response ) { - if ( filter.length > bestMatchFilter.length ) { - bestMatchFilter = filter; - } + if ( filter.length <= bestMatchFilter.length ) { continue; } + bestMatchFilter = filter; } if ( bestMatchFilter !== '' && @@ -1622,14 +1618,14 @@ if ( dom.cl.has(targetRow, 'networkRealm') ) { const response = await messaging.send('loggerUI', { what: 'listsFromNetFilter', - rawFilter: rawFilter, + rawFilter, }); handleResponse(response); } else if ( dom.cl.has(targetRow, 'extendedRealm') ) { const response = await messaging.send('loggerUI', { what: 'listsFromCosmeticFilter', url: targetRow.children[COLUMN_URL].textContent, - rawFilter: rawFilter, + rawFilter, }); handleResponse(response); } @@ -2156,7 +2152,7 @@ reStr = rawPart.slice(1, -1); try { new RegExp(reStr); - } catch(ex) { + } catch { reStr = ''; } } @@ -2835,7 +2831,7 @@ }; const setRadioButton = function(group, value) { - if ( hasOwnProperty(options, group) === false ) { return; } + if ( Object.hasOwn(options, group) === false ) { return; } const groupEl = qs$(dialog, `[data-radio="${group}"]`); const buttonEls = qsa$(groupEl, '[data-radio-item]'); for ( const buttonEl of buttonEls ) { @@ -2937,7 +2933,7 @@ if ( Array.isArray(stored.columns) ) { settings.columns = stored.columns; } - } catch(_) { + } catch { } }); diff -Nru ublock-origin-1.62.0+dfsg/src/js/logger.js ublock-origin-1.67.0+dfsg/src/js/logger.js --- ublock-origin-1.62.0+dfsg/src/js/logger.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/logger.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,10 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - import { broadcast, broadcastToAll } from './broadcast.js'; /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/src/js/lz4.js ublock-origin-1.67.0+dfsg/src/js/lz4.js --- ublock-origin-1.62.0+dfsg/src/js/lz4.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/lz4.js 2025-10-25 19:32:51.000000000 +0000 @@ -21,10 +21,6 @@ /* global lz4BlockCodec */ -'use strict'; - -/******************************************************************************/ - import µb from './background.js'; /******************************************************************************* diff -Nru ublock-origin-1.62.0+dfsg/src/js/messaging.js ublock-origin-1.67.0+dfsg/src/js/messaging.js --- ublock-origin-1.62.0+dfsg/src/js/messaging.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/messaging.js 2025-10-25 19:32:51.000000000 +0000 @@ -25,7 +25,6 @@ import { domainFromHostname, domainFromURI, - entityFromDomain, hostnameFromURI, isNetworkURI, } from './uri-utils.js'; @@ -52,16 +51,13 @@ import punycode from '../lib/punycode.js'; import { redirectEngine } from './redirect-engine.js'; import scriptletFilteringEngine from './scriptlet-filtering.js'; -import staticFilteringReverseLookup from './reverselookup.js'; +import { staticFilteringReverseLookup } from './reverselookup.js'; import staticNetFilteringEngine from './static-net-filtering.js'; import webRequest from './traffic.js'; import µb from './background.js'; /******************************************************************************/ -const hasOwnProperty = (o, p) => - Object.prototype.hasOwnProperty.call(o, p); - // https://github.com/uBlockOrigin/uBlock-issues/issues/710 // Listeners have a name and a "privileged" status. // The nameless default handler is always deemed "privileged". @@ -684,7 +680,7 @@ request.frameId = frameId; request.hostname = hostnameFromURI(request.url); request.domain = domainFromHostname(request.hostname); - request.entity = entityFromDomain(request.domain); + request.ancestors = pageStore.getFrameAncestorDetails(frameId); const scf = response.specificCosmeticFilters = cosmeticFilteringEngine.retrieveSpecificSelectors(request, response); @@ -918,7 +914,7 @@ let u8array; try { u8array = denseBase64.decode(encoded); - } catch(ex) { + } catch { } return Promise.resolve(u8array !== undefined ? u8array : encoded); }; @@ -1096,7 +1092,7 @@ // Discard unknown setting or setting with default value. for ( const key in hiddenSettings ) { if ( - hasOwnProperty(µb.hiddenSettingsDefault, key) === false || + Object.hasOwn(µb.hiddenSettingsDefault, key) === false || hiddenSettings[key] === µb.hiddenSettingsDefault[key] ) { delete hiddenSettings[key]; @@ -1148,7 +1144,7 @@ // Filter lists const prepListEntries = function(entries) { for ( const k in entries ) { - if ( hasOwnProperty(entries, k) === false ) { continue; } + if ( Object.hasOwn(entries, k) === false ) { continue; } const entry = entries[k]; if ( typeof entry.supportURL === 'string' && entry.supportURL !== '' ) { entry.supportName = hostnameFromURI(entry.supportURL); @@ -1336,7 +1332,7 @@ let addedListset = {}; let removedListset = {}; for ( const listKey in lists ) { - if ( hasOwnProperty(lists, listKey) === false ) { continue; } + if ( Object.hasOwn(lists, listKey) === false ) { continue; } const list = lists[listKey]; if ( list.content !== 'filters' ) { continue; } const used = µb.selectedFilterLists.includes(listKey); @@ -1890,7 +1886,9 @@ return { name: assetKey, text: details.content, - trustedSource: assetKey.startsWith('ublock-'), + trustedSource: assetKey.startsWith('ublock-') || + assetKey === µb.userFiltersPath && + µb.userSettings.userFiltersTrusted, }; }) ); diff -Nru ublock-origin-1.62.0+dfsg/src/js/mrucache.js ublock-origin-1.67.0+dfsg/src/js/mrucache.js --- ublock-origin-1.62.0+dfsg/src/js/mrucache.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/mrucache.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - export class MRUCache { constructor(maxSize) { this.maxSize = maxSize; diff -Nru ublock-origin-1.62.0+dfsg/src/js/pagestore.js ublock-origin-1.67.0+dfsg/src/js/pagestore.js --- ublock-origin-1.62.0+dfsg/src/js/pagestore.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/pagestore.js 2025-10-25 19:32:51.000000000 +0000 @@ -535,6 +535,21 @@ return sender.frameURL; } + getFrameAncestorDetails(frameId) { + if ( frameId === 0 ) { return []; } + const out = []; + for (;;) { + const frameStore = this.getFrameStore(frameId); + if ( frameStore === null ) { break; } + const { domain, hostname } = frameStore; + if ( hostname !== undefined ) { + out.push({ domain, hostname }); + } + frameId = frameStore.parentId; + } + return out.slice(1); + } + // There is no event to tell us a specific subframe has been removed from // the main document. The code below will remove subframes which are no // longer present in the root document. Removing obsolete subframes is @@ -549,7 +564,7 @@ entries = await webext.webNavigation.getAllFrames({ tabId: this.tabId }); - } catch(ex) { + } catch { } if ( Array.isArray(entries) === false ) { return; } const toKeep = new Set(); @@ -941,7 +956,7 @@ redirectNonBlockedRequest(fctxt) { const directives = []; - staticNetFilteringEngine.transformRequest(fctxt, directives); + staticNetFilteringEngine.transformURL(fctxt, directives); if ( staticNetFilteringEngine.hasQuery(fctxt) ) { staticNetFilteringEngine.filterQuery(fctxt, directives); } @@ -961,14 +976,12 @@ skipMainDocument(fctxt, blocked) { const directives = staticNetFilteringEngine.urlSkip(fctxt, blocked); if ( directives === undefined ) { return; } - if ( logger.enabled !== true ) { return; } fctxt.pushFilters(directives.map(a => a.logData())); - if ( fctxt.redirectURL !== undefined ) { - fctxt.pushFilter({ - source: 'redirect', - raw: fctxt.redirectURL - }); - } + if ( fctxt.redirectURL === undefined ) { return; } + fctxt.pushFilter({ + source: 'redirect', + raw: fctxt.redirectURL + }); } filterCSPReport(fctxt) { diff -Nru ublock-origin-1.62.0+dfsg/src/js/popup-fenix.js ublock-origin-1.67.0+dfsg/src/js/popup-fenix.js --- ublock-origin-1.62.0+dfsg/src/js/popup-fenix.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/popup-fenix.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,11 +19,9 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -import punycode from '../lib/punycode.js'; -import { i18n$ } from './i18n.js'; import { dom, qs$, qsa$ } from './dom.js'; +import { i18n$ } from './i18n.js'; +import punycode from '../lib/punycode.js'; /******************************************************************************/ @@ -58,6 +56,7 @@ let dfHotspots = null; const allHostnameRows = []; let cachedPopupHash = ''; +let forceReloadFlag = 0; // https://github.com/gorhill/uBlock/issues/2550 // Solution inspired from @@ -70,9 +69,6 @@ const reCyrillicNonAmbiguous = /[\u0400-\u042b\u042d-\u042f\u0431\u0432\u0434\u0436-\u043d\u0442\u0444\u0446-\u0449\u044b-\u0454\u0457\u0459-\u0460\u0462-\u0474\u0476-\u04ba\u04bc\u04be-\u04ce\u04d0-\u0500\u0502-\u051a\u051c\u051e-\u052f]/; const reCyrillicAmbiguous = /[\u042c\u0430\u0433\u0435\u043e\u043f\u0440\u0441\u0443\u0445\u044a\u0455\u0456\u0458\u0461\u0475\u04bb\u04bd\u04cf\u0501\u051b\u051d]/; -const hasOwnProperty = (o, p) => - Object.prototype.hasOwnProperty.call(o, p); - /******************************************************************************/ const cachePopupData = function(data) { @@ -91,7 +87,7 @@ return popupData; } for ( const hostname in hostnameDict ) { - if ( hasOwnProperty(hostnameDict, hostname) === false ) { continue; } + if ( Object.hasOwn(hostnameDict, hostname) === false ) { continue; } let domain = hostnameDict[hostname].domain; let prefix = hostname.slice(0, 0 - domain.length - 1); // Prefix with space char for 1st-party hostnames: this ensure these @@ -135,6 +131,7 @@ const hash = hasher.join(''); if ( reset ) { cachedPopupHash = hash; + forceReloadFlag = 0; } dom.cl.toggle(dom.body, 'needReload', hash !== cachedPopupHash || popupData.hasUnprocessedRequest === true @@ -163,7 +160,7 @@ }); if ( intl.resolvedOptions instanceof Function && - hasOwnProperty(intl.resolvedOptions(), 'notation') + Object.hasOwn(intl.resolvedOptions(), 'notation') ) { intlNumberFormat = intl; } @@ -178,11 +175,11 @@ // a poor's man compact form, which unfortunately is not i18n-friendly. count /= 1000000; if ( count >= 100 ) { - count = Math.floor(count * 10) / 10; + count = Math.floor(count * 10) / 10; } else if ( count > 10 ) { - count = Math.floor(count * 100) / 100; + count = Math.floor(count * 100) / 100; } else { - count = Math.floor(count * 1000) / 1000; + count = Math.floor(count * 1000) / 1000; } return (count).toLocaleString(undefined) + '\u2009M'; }; @@ -469,27 +466,27 @@ for ( const elem of elems ) { const on = dom.cl.has(elem, 'on'); switch ( elem.dataset.expr ) { - case 'not': - not = on; - break; - case 'blocked': - dom.cl.toggle(firewallElem, 'showBlocked', !not && on); - dom.cl.toggle(firewallElem, 'hideBlocked', not && on); - break; - case 'allowed': - dom.cl.toggle(firewallElem, 'showAllowed', !not && on); - dom.cl.toggle(firewallElem, 'hideAllowed', not && on); - break; - case 'script': - dom.cl.toggle(firewallElem, 'show3pScript', !not && on); - dom.cl.toggle(firewallElem, 'hide3pScript', not && on); - break; - case 'frame': - dom.cl.toggle(firewallElem, 'show3pFrame', !not && on); - dom.cl.toggle(firewallElem, 'hide3pFrame', not && on); - break; - default: - break; + case 'not': + not = on; + break; + case 'blocked': + dom.cl.toggle(firewallElem, 'showBlocked', !not && on); + dom.cl.toggle(firewallElem, 'hideBlocked', not && on); + break; + case 'allowed': + dom.cl.toggle(firewallElem, 'showAllowed', !not && on); + dom.cl.toggle(firewallElem, 'hideAllowed', not && on); + break; + case 'script': + dom.cl.toggle(firewallElem, 'show3pScript', !not && on); + dom.cl.toggle(firewallElem, 'hide3pScript', not && on); + break; + case 'frame': + dom.cl.toggle(firewallElem, 'show3pFrame', !not && on); + dom.cl.toggle(firewallElem, 'hide3pFrame', not && on); + break; + default: + break; } } } @@ -498,14 +495,14 @@ const target = ev.target; dom.cl.toggle(target, 'on'); switch ( target.dataset.expr ) { - case 'blocked': - if ( dom.cl.has(target, 'on') === false ) { break; } - dom.cl.remove('#firewall .filterExpressions span[data-expr="allowed"]', 'on'); - break; - case 'allowed': - if ( dom.cl.has(target, 'on') === false ) { break; } - dom.cl.remove('#firewall .filterExpressions span[data-expr="blocked"]', 'on'); - break; + case 'blocked': + if ( dom.cl.has(target, 'on') === false ) { break; } + dom.cl.remove('#firewall .filterExpressions span[data-expr="allowed"]', 'on'); + break; + case 'allowed': + if ( dom.cl.has(target, 'on') === false ) { break; } + dom.cl.remove('#firewall .filterExpressions span[data-expr="blocked"]', 'on'); + break; } filterFirewallRows(); const elems = qsa$('#firewall .filterExpressions span[data-expr]'); @@ -548,7 +545,7 @@ if ( des === '*' || desHostnameDone.has(des) ) { continue; } const hnDetails = hostnameDict[des]; const { domain, counts } = hnDetails; - if ( hasOwnProperty(allDomains, domain) === false ) { + if ( Object.hasOwn(allDomains, domain) === false ) { allDomains[domain] = false; allDomainCount += 1; } @@ -1172,7 +1169,7 @@ tabId: popupData.tabId, url: popupData.rawURL, select: vAPI.webextFlavor.soup.has('mobile'), - bypassCache, + bypassCache: bypassCache || forceReloadFlag !== 0, }); // Polling will take care of refreshing the popup content @@ -1194,18 +1191,18 @@ if ( ev.isComposing ) { return; } let bypassCache = false; switch ( ev.key ) { - case 'F5': - bypassCache = ev.ctrlKey || ev.metaKey || ev.shiftKey; - break; - case 'r': - if ( (ev.ctrlKey || ev.metaKey) !== true ) { return; } - break; - case 'R': - if ( (ev.ctrlKey || ev.metaKey) !== true ) { return; } - bypassCache = true; - break; - default: - return; + case 'F5': + bypassCache = ev.ctrlKey || ev.metaKey || ev.shiftKey; + break; + case 'r': + if ( (ev.ctrlKey || ev.metaKey) !== true ) { return; } + break; + case 'R': + if ( (ev.ctrlKey || ev.metaKey) !== true ) { return; } + bypassCache = true; + break; + default: + return; } reloadTab(bypassCache); ev.preventDefault(); @@ -1223,7 +1220,7 @@ expandExceptions.add(exception); } } - catch(ex) { + catch { } }); @@ -1349,6 +1346,10 @@ persist: ev.ctrlKey || ev.metaKey, }); + if ( switchName === 'no-scripting' ) { + forceReloadFlag ^= 1; + } + cachePopupData(response); hashFromPopupData(); diff -Nru ublock-origin-1.62.0+dfsg/src/js/redirect-engine.js ublock-origin-1.67.0+dfsg/src/js/redirect-engine.js --- ublock-origin-1.62.0+dfsg/src/js/redirect-engine.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/redirect-engine.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,12 +19,8 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - -import redirectableResources from './redirect-resources.js'; import { LineIterator, orphanizeString } from './text-utils.js'; +import redirectableResources from './redirect-resources.js'; /******************************************************************************/ @@ -214,6 +210,7 @@ const entry = this.resources.get(this.aliases.get(name) || name); if ( entry === undefined ) { return; } if ( entry.mime.startsWith(mime) === false ) { return; } + if ( entry.data === undefined ) { return; } return { js: entry.toContent(), world: entry.world, @@ -464,6 +461,7 @@ for ( const [ token, entry ] of this.resources ) { this.resources.set(token, RedirectEntry.fromDetails(entry)); } + this.modifyTime = Date.now(); return true; } diff -Nru ublock-origin-1.62.0+dfsg/src/js/redirect-resources.js ublock-origin-1.67.0+dfsg/src/js/redirect-resources.js --- ublock-origin-1.62.0+dfsg/src/js/redirect-resources.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/redirect-resources.js 2025-10-25 19:32:51.000000000 +0000 @@ -94,6 +94,7 @@ } ], [ 'google-ima.js', { alias: 'google-ima3', /* adguard compatibility */ + data: 'text', } ], [ 'googlesyndication_adsbygoogle.js', { alias: [ diff -Nru ublock-origin-1.62.0+dfsg/src/js/regex-analyzer.js ublock-origin-1.67.0+dfsg/src/js/regex-analyzer.js --- ublock-origin-1.62.0+dfsg/src/js/regex-analyzer.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/regex-analyzer.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,256 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2020-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import Regex from '../lib/regexanalyzer/regex.js'; + +/******************************************************************************/ + +// Depends on: +// https://github.com/foo123/RegexAnalyzer +const RegexAnalyzer = Regex && Regex.Analyzer || null; + +export function isRE2(reStr) { + if ( RegexAnalyzer === null ) { return true; } + try { + return _isRE2(RegexAnalyzer(reStr, false).tree()); + } catch { + } + return false; +} + +export function tokenizableStrFromRegex(reStr) { + return _literalStrFromRegex(reStr); +} + +/******************************************************************************/ + +function _isRE2(node) { + if ( node instanceof Object === false ) { return true; } + if ( node.flags instanceof Object ) { + if ( node.flags.LookAhead === 1 ) { return false; } + if ( node.flags.NegativeLookAhead === 1 ) { return false; } + if ( node.flags.LookBehind === 1 ) { return false; } + if ( node.flags.NegativeLookBehind === 1 ) { return false; } + } + if ( Array.isArray(node.val) ) { + for ( const entry of node.val ) { + if ( _isRE2(entry) === false ) { return false; } + } + } + if ( node.val instanceof Object ) { + return _isRE2(node.val); + } + return true; +} + +/******************************************************************************/ + +function _literalStrFromRegex(reStr) { + if ( RegexAnalyzer === null ) { return ''; } + let s = ''; + try { + s = tokenizableStrFromNode( + RegexAnalyzer(reStr, false).tree() + ); + } catch { + } + // Process optional sequences + const reOptional = /[\x02\x03]+/; + for (;;) { + const match = reOptional.exec(s); + if ( match === null ) { break; } + const left = s.slice(0, match.index); + const middle = match[0]; + const right = s.slice(match.index + middle.length); + s = left; + s += firstCharCodeClass(right) === 1 || firstCharCodeClass(middle) === 1 + ? '\x01' + : '\x00'; + s += lastCharCodeClass(left) === 1 || lastCharCodeClass(middle) === 1 + ? '\x01' + : '\x00'; + s += right; + } + return s; +} + +function firstCharCodeClass(s) { + if ( s.length === 0 ) { return 0; } + const c = s.charCodeAt(0); + if ( c === 1 || c === 3 ) { return 1; } + return reCharCodeClass.test(s.charAt(0)) ? 1 : 0; +} + +function lastCharCodeClass(s) { + const i = s.length - 1; + if ( i === -1 ) { return 0; } + const c = s.charCodeAt(i); + if ( c === 1 || c === 3 ) { return 1; } + return reCharCodeClass.test(s.charAt(i)) ? 1 : 0; +} + +const reCharCodeClass = /[%0-9A-Za-z]/; + +function tokenizableStrFromNode(node) { + switch ( node.type ) { + case 1: /* T_SEQUENCE, 'Sequence' */ { + let s = ''; + for ( let i = 0; i < node.val.length; i++ ) { + s += tokenizableStrFromNode(node.val[i]); + } + return s; + } + case 2: /* T_ALTERNATION, 'Alternation' */ + case 8: /* T_CHARGROUP, 'CharacterGroup' */ { + if ( node.flags.NegativeMatch ) { return '\x01'; } + let firstChar = 0; + let lastChar = 0; + for ( let i = 0; i < node.val.length; i++ ) { + const s = tokenizableStrFromNode(node.val[i]); + if ( firstChar === 0 && firstCharCodeClass(s) === 1 ) { + firstChar = 1; + } + if ( lastChar === 0 && lastCharCodeClass(s) === 1 ) { + lastChar = 1; + } + if ( firstChar === 1 && lastChar === 1 ) { break; } + } + return String.fromCharCode(firstChar, lastChar); + } + case 4: /* T_GROUP, 'Group' */ { + if ( + node.flags.NegativeLookAhead === 1 || + node.flags.NegativeLookBehind === 1 + ) { + return ''; + } + return tokenizableStrFromNode(node.val); + } + case 16: /* T_QUANTIFIER, 'Quantifier' */ { + if ( node.flags.max === 0 ) { return ''; } + const s = tokenizableStrFromNode(node.val); + const first = firstCharCodeClass(s); + const last = lastCharCodeClass(s); + if ( node.flags.min !== 0 ) { + return String.fromCharCode(first, last); + } + return String.fromCharCode(first+2, last+2); + } + case 64: /* T_HEXCHAR, 'HexChar' */ { + if ( + node.flags.Code === '01' || + node.flags.Code === '02' || + node.flags.Code === '03' + ) { + return '\x00'; + } + return node.flags.Char; + } + case 128: /* T_SPECIAL, 'Special' */ { + const flags = node.flags; + if ( + flags.EndCharGroup === 1 || // dangling `]` + flags.EndGroup === 1 || // dangling `)` + flags.EndRepeats === 1 // dangling `}` + ) { + throw new Error('Unmatched bracket'); + } + return flags.MatchEnd === 1 || + flags.MatchStart === 1 || + flags.MatchWordBoundary === 1 + ? '\x00' + : '\x01'; + } + case 256: /* T_CHARS, 'Characters' */ { + for ( let i = 0; i < node.val.length; i++ ) { + if ( firstCharCodeClass(node.val[i]) === 1 ) { + return '\x01'; + } + } + return '\x00'; + } + // Ranges are assumed to always involve token-related characters. + case 512: /* T_CHARRANGE, 'CharacterRange' */ { + return '\x01'; + } + case 1024: /* T_STRING, 'String' */ { + return node.val; + } + case 2048: /* T_COMMENT, 'Comment' */ { + return ''; + } + default: + break; + } + return '\x01'; +} + +/******************************************************************************/ + +export function toHeaderPattern(reStr) { + if ( RegexAnalyzer === null ) { return; } + try { + return _toHeaderPattern(RegexAnalyzer(reStr, false).tree()); + } catch { + } +} + +function _toHeaderPattern(branch, depth = 0) { + switch ( branch.type ) { + case 1: /* T_SEQUENCE, 'Sequence' */ { + let s = ''; + for ( const node of branch.val ) { + const t = _toHeaderPattern(node, depth+1); + if ( t === undefined ) { return; } + s += t; + } + if ( depth === 0 && branch.val.length !== 0 ) { + const first = branch.val[0]; + if ( first.type !== 128 || first.val !== '^' ) { s = `*${s}`; } + const last = branch.val.at(-1); + if ( last.type !== 128 || last.val !== '$' ) { s = `${s}*`; } + } + return s; + } + case 4: /* T_GROUP, 'Group' */ { + if ( + branch.flags.NegativeLookAhead === 1 || + branch.flags.NegativeLookBehind === 1 + ) { + return; + } + return _toHeaderPattern(branch.val, depth+1); + } + case 64: /* T_HEXCHAR, 'HexChar' */ + return branch.flags.Char; + case 128: /* T_SPECIAL, 'Special' */ { + if ( branch.val === '^' ) { return ''; } + if ( branch.val === '$' ) { return ''; } + return; + } + case 1024: /* T_STRING, 'String' */ + return branch.val; + case 2048: /* T_COMMENT, 'Comment' */ + return ''; + default: + break; + } +} diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/attribute.js ublock-origin-1.67.0+dfsg/src/js/resources/attribute.js --- ublock-origin-1.62.0+dfsg/src/js/resources/attribute.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/attribute.js 2025-10-25 19:32:51.000000000 +0000 @@ -49,7 +49,7 @@ let elems; try { elems = document.querySelectorAll(selector); - } catch(_) { + } catch { return false; } for ( const elem of elems ) { @@ -259,7 +259,7 @@ safe.uboLog(logPrefix, `Removed attribute '${attr}'`); } } - } catch(ex) { + } catch { } }; const mutationHandler = mutations => { diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/cookie.js ublock-origin-1.67.0+dfsg/src/js/resources/cookie.js --- ublock-origin-1.62.0+dfsg/src/js/resources/cookie.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/cookie.js 2025-10-25 19:32:51.000000000 +0000 @@ -46,6 +46,9 @@ 'yes', 'y', 'no', 'n', 'all', 'none', 'functional', 'granted', 'done', + 'decline', 'declined', + 'closed', 'next', 'mandatory', + 'disagree', 'agree', ]; } registerScriptlet(getSafeCookieValuesFn, { @@ -132,7 +135,16 @@ if ( trusted ) { if ( options.domain ) { - cookieParts.push(`; domain=${options.domain}`); + let domain = options.domain; + if ( /^\/.+\//.test(domain) ) { + const baseURL = new URL(document.baseURI); + const reDomain = new RegExp(domain.slice(1, -1)); + const match = reDomain.exec(baseURL.hostname); + domain = match ? match[0] : undefined; + } + if ( domain ) { + cookieParts.push(`; domain=${domain}`); + } } cookieParts.push('; Secure'); } else if ( /^__(Host|Secure)-/.test(name) ) { @@ -141,7 +153,7 @@ try { document.cookie = cookieParts.join(''); - } catch(_) { + } catch { } const done = getCookieFn(name) === value; @@ -358,6 +370,13 @@ fn(); }, ms); }; + const baseURL = new URL(document.baseURI); + let targetDomain = extraArgs.domain; + if ( targetDomain && /^\/.+\//.test(targetDomain) ) { + const reDomain = new RegExp(targetDomain.slice(1, -1)); + const match = reDomain.exec(baseURL.hostname); + targetDomain = match ? match[0] : undefined; + } const remove = ( ) => { safe.String_split.call(document.cookie, ';').forEach(cookieStr => { const pos = cookieStr.indexOf('='); @@ -365,16 +384,19 @@ const cookieName = cookieStr.slice(0, pos).trim(); if ( reName.test(cookieName) === false ) { return; } const part1 = cookieName + '='; - const part2a = '; domain=' + document.location.hostname; - const part2b = '; domain=.' + document.location.hostname; + const part2a = `; domain=${baseURL.hostname}`; + const part2b = `; domain=.${baseURL.hostname}`; let part2c, part2d; - const domain = document.domain; - if ( domain ) { - if ( domain !== document.location.hostname ) { - part2c = '; domain=.' + domain; + if ( targetDomain ) { + part2c = `; domain=${targetDomain}`; + part2d = `; domain=.${targetDomain}`; + } else if ( document.domain ) { + const domain = document.domain; + if ( domain !== baseURL.hostname ) { + part2c = `; domain=.${domain}`; } if ( domain.startsWith('www.') ) { - part2d = '; domain=' + domain.replace('www', ''); + part2d = `; domain=${domain.replace('www', '')}`; } } const part3 = '; path=/'; diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/create-html.js ublock-origin-1.67.0+dfsg/src/js/resources/create-html.js --- ublock-origin-1.62.0+dfsg/src/js/resources/create-html.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/create-html.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,113 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock + +*/ + +import { registerScriptlet } from './base.js'; +import { safeSelf } from './safe-self.js'; + +/******************************************************************************/ + +/** + * @scriptlet trusted-create-html + * + * @description + * Element(s) from a parsed HTML string are added as child element(s) to a + * specific parent element in the DOM. + * + * @param parent + * A CSS selector identifying the element to which created element(s) will be + * added. + * + * @param html + * An HTML string to be parsed using DOMParser, and which resulting elements + * are to be added as child element(s). + * + * @param duration + * Optional. If specified, the time in ms after which the added elements will + * be removed. No removal will occur if not specified. + * + * */ + +function trustedCreateHTML( + parentSelector, + htmlStr = '', + durationStr = '' +) { + if ( parentSelector === '' ) { return; } + if ( htmlStr === '' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('trusted-create-html', parentSelector, htmlStr, durationStr); + // We do not want to recursively create elements + self.trustedCreateHTML = true; + let ancestor = self.frameElement; + while ( ancestor !== null ) { + const doc = ancestor.ownerDocument; + if ( doc === null ) { break; } + const win = doc.defaultView; + if ( win === null ) { break; } + if ( win.trustedCreateHTML ) { return; } + ancestor = ancestor.frameElement; + } + const duration = parseInt(durationStr, 10); + const domParser = new DOMParser(); + const externalDoc = domParser.parseFromString(htmlStr, 'text/html'); + const docFragment = new DocumentFragment(); + const toRemove = []; + while ( externalDoc.body.firstChild !== null ) { + const imported = document.adoptNode(externalDoc.body.firstChild); + docFragment.appendChild(imported); + if ( isNaN(duration) ) { continue; } + toRemove.push(imported); + } + if ( docFragment.firstChild === null ) { return; } + const remove = ( ) => { + for ( const node of toRemove ) { + if ( node.parentNode === null ) { continue; } + node.parentNode.removeChild(node); + } + safe.uboLog(logPrefix, 'Node(s) removed'); + }; + const append = ( ) => { + const parent = document.querySelector(parentSelector); + if ( parent === null ) { return false; } + parent.append(docFragment); + safe.uboLog(logPrefix, 'Node(s) appended'); + if ( toRemove.length === 0 ) { return true; } + setTimeout(remove, duration); + return true; + }; + if ( append() ) { return; } + const observer = new MutationObserver(( ) => { + if ( append() === false ) { return; } + observer.disconnect(); + }); + observer.observe(document, { childList: true, subtree: true }); +} +registerScriptlet(trustedCreateHTML, { + name: 'trusted-create-html.js', + requiresTrust: true, + dependencies: [ + safeSelf, + ], + world: 'ISOLATED', +}); + +/******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/href-sanitizer.js ublock-origin-1.67.0+dfsg/src/js/resources/href-sanitizer.js --- ublock-origin-1.62.0+dfsg/src/js/resources/href-sanitizer.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/href-sanitizer.js 2025-10-25 19:32:51.000000000 +0000 @@ -73,7 +73,7 @@ try { elems = document.querySelectorAll(`a[href="${href}"`); } - catch(ex) { + catch { } for ( const elem of elems ) { elem.setAttribute('href', text); @@ -87,39 +87,21 @@ try { const url = new URL(text, document.location); return url.href; - } catch(ex) { + } catch { } return ''; }; - const extractParam = (href, source) => { - if ( Boolean(source) === false ) { return href; } - const recursive = source.includes('?', 1); - const end = recursive ? source.indexOf('?', 1) : source.length; - try { - const url = new URL(href, document.location); - let value = url.searchParams.get(source.slice(1, end)); - if ( value === null ) { return href } - if ( recursive ) { return extractParam(value, source.slice(end)); } - return value; - } catch(x) { - } - return href; - }; const extractURL = (elem, source) => { if ( /^\[.*\]$/.test(source) ) { return elem.getAttribute(source.slice(1,-1).trim()) || ''; } if ( source === 'text' ) { return elem.textContent - .replace(/^[^\x21-\x7e]+/, '') // remove leading invalid characters - .replace(/[^\x21-\x7e]+$/, '') // remove trailing invalid characters - ; - } - if ( source.startsWith('?') === false ) { return ''; } - const steps = source.replace(/(\S)\?/g, '\\1?').split(/\s+/); - const url = steps.length === 1 - ? extractParam(elem.href, source) - : urlSkip(elem.href, false, steps); + .replace(/^[^\x21-\x7e]+/, '') // remove leading invalid characters + .replace(/[^\x21-\x7e]+$/, ''); // remove trailing invalid characters + } + const steps = source.replace(/(\S)\?/g, '\\1 ?').split(/\s+/); + const url = urlSkip(elem.href, false, steps); if ( url === undefined ) { return; } return url.replace(/ /g, '%20'); }; @@ -128,7 +110,7 @@ try { elems = document.querySelectorAll(selector); } - catch(ex) { + catch { return false; } for ( const elem of elems ) { diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/json-edit.js ublock-origin-1.67.0+dfsg/src/js/resources/json-edit.js --- ublock-origin-1.62.0+dfsg/src/js/resources/json-edit.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/json-edit.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,1105 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2019-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock + +*/ + +import { + matchObjectPropertiesFn, + parsePropertiesToMatchFn, +} from './utils.js'; + +import { JSONPath } from './shared.js'; +import { proxyApplyFn } from './proxy-apply.js'; +import { registerScriptlet } from './base.js'; +import { safeSelf } from './safe-self.js'; + +/******************************************************************************/ +/******************************************************************************/ + +function editOutboundObjectFn( + trusted = false, + propChain = '', + jsonq = '', +) { + if ( propChain === '' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix( + `${trusted ? 'trusted-' : ''}edit-outbound-object`, + propChain, + jsonq + ); + const jsonp = JSONPath.create(jsonq); + if ( jsonp.valid === false || jsonp.value !== undefined && trusted !== true ) { + return safe.uboLog(logPrefix, 'Bad JSONPath query'); + } + proxyApplyFn(propChain, function(context) { + const obj = context.reflect(); + const objAfter = jsonp.apply(obj); + if ( objAfter === undefined ) { return obj; } + safe.uboLog(logPrefix, 'Edited'); + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `After edit:\n${safe.JSON_stringify(objAfter, null, 2)}`); + } + return objAfter; + }); +} +registerScriptlet(editOutboundObjectFn, { + name: 'edit-outbound-object.fn', + dependencies: [ + JSONPath, + proxyApplyFn, + safeSelf, + ], +}); + +/******************************************************************************/ +/** + * @scriptlet edit-outbound-object-.js + * + * @description + * Prune properties from an object returned by a specific method. + * Properties can only be removed. + * + * @param propChain + * Property chain of the method to trap. + * + * @param jsonq + * A uBO-flavored JSONPath query. + * + * */ + +function editOutboundObject(propChain = '', jsonq = '') { + editOutboundObjectFn(false, propChain, jsonq); +} +registerScriptlet(editOutboundObject, { + name: 'edit-outbound-object.js', + dependencies: [ + editOutboundObjectFn, + ], +}); + +/******************************************************************************/ +/** + * @scriptlet trusted-edit-outbound-object.js + * + * @description + * Edit properties of an object returned by a specific method. + * Properties can be assigned new values. + * + * @param propChain + * Property chain of the method to trap. + * +* @param jsonq + * A uBO-flavored JSONPath query. + * + * */ + +function trustedEditOutboundObject(propChain = '', jsonq = '') { + editOutboundObjectFn(true, propChain, jsonq); +} +registerScriptlet(trustedEditOutboundObject, { + name: 'trusted-edit-outbound-object.js', + requiresTrust: true, + dependencies: [ + editOutboundObjectFn, + ], +}); + +/******************************************************************************/ +/******************************************************************************/ +/** + * @scriptlet json-edit.js + * + * @description + * Edit object generated through JSON.parse(). + * Properties can only be removed. + * + * @param jsonq + * A uBO-flavored JSONPath query. + * + * */ + +function jsonEdit(jsonq = '') { + editOutboundObjectFn(false, 'JSON.parse', jsonq); +} +registerScriptlet(jsonEdit, { + name: 'json-edit.js', + dependencies: [ + editOutboundObjectFn, + ], +}); + +/******************************************************************************/ +/** + * @scriptlet trusted-json-edit.js + * + * @description + * Edit object generated through JSON.parse(). + * Properties can be assigned new values. + * + * @param jsonq + * A uBO-flavored JSONPath query. + * + * */ + +function trustedJsonEdit(jsonq = '') { + editOutboundObjectFn(true, 'JSON.parse', jsonq); +} +registerScriptlet(trustedJsonEdit, { + name: 'trusted-json-edit.js', + requiresTrust: true, + dependencies: [ + editOutboundObjectFn, + ], +}); + +/******************************************************************************/ +/******************************************************************************/ + +function editInboundObjectFn( + trusted = false, + propChain = '', + argPosRaw = '', + jsonq = '', +) { + if ( propChain === '' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix( + `${trusted ? 'trusted-' : ''}edit-inbound-object`, + propChain, + jsonq + ); + const jsonp = JSONPath.create(jsonq); + if ( jsonp.valid === false || jsonp.value !== undefined && trusted !== true ) { + return safe.uboLog(logPrefix, 'Bad JSONPath query'); + } + const argPos = parseInt(argPosRaw, 10); + if ( isNaN(argPos) ) { return; } + const getArgPos = args => { + if ( argPos >= 0 ) { + if ( args.length <= argPos ) { return; } + return argPos; + } + if ( args.length < -argPos ) { return; } + return args.length + argPos; + }; + const editObj = obj => { + let clone; + try { + clone = safe.JSON_parse(safe.JSON_stringify(obj)); + } catch { + } + if ( typeof clone !== 'object' || clone === null ) { return; } + const objAfter = jsonp.apply(clone); + if ( objAfter === undefined ) { return; } + safe.uboLog(logPrefix, 'Edited'); + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `After edit:\n${safe.JSON_stringify(objAfter, null, 2)}`); + } + return objAfter; + }; + proxyApplyFn(propChain, function(context) { + const i = getArgPos(context.callArgs); + if ( i !== undefined ) { + const obj = editObj(context.callArgs[i]); + if ( obj ) { + context.callArgs[i] = obj; + } + } + return context.reflect(); + }); +} +registerScriptlet(editInboundObjectFn, { + name: 'edit-inbound-object.fn', + dependencies: [ + JSONPath, + proxyApplyFn, + safeSelf, + ], +}); + +/******************************************************************************/ +/** + * @scriptlet edit-inbound-object.js + * + * @description + * Prune properties from an object passed as argument to a specific method. + * Properties can only be removed. + * + * @param propChain + * Property chain of the method to trap. + * + * @param argPos + * 0-based position of the argument. Use negative integer for position relative + * to the end. + * + * @param jsonq + * A uBO-flavored JSONPath query. + * + * */ + +function editInboundObject(propChain = '', argPos = '', jsonq = '') { + editInboundObjectFn(false, propChain, argPos, jsonq); +} +registerScriptlet(editInboundObject, { + name: 'edit-inbound-object.js', + dependencies: [ + editInboundObjectFn, + ], +}); + +/******************************************************************************/ +/** + * @scriptlet trusted-edit-inbound-object.js + * + * @description + * Edit properties of an object passed as argument to a specific method. + * Properties can be assigned new values. + * + * @param propChain + * Property chain of the method to trap. + * + * @param argPos + * 0-based position of the argument. Use negative integer for position relative + * to the end. + * + * @param jsonq + * A uBO-flavored JSONPath query. + * + * */ + +function trustedEditInboundObject(propChain = '', argPos = '', jsonq = '') { + editInboundObjectFn(true, propChain, argPos, jsonq); +} +registerScriptlet(trustedEditInboundObject, { + name: 'trusted-edit-inbound-object.js', + requiresTrust: true, + dependencies: [ + editInboundObjectFn, + ], +}); + +/******************************************************************************/ +/******************************************************************************/ + +function jsonEditXhrResponseFn(trusted, jsonq = '') { + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix( + `${trusted ? 'trusted-' : ''}json-edit-xhr-response`, + jsonq + ); + const xhrInstances = new WeakMap(); + const jsonp = JSONPath.create(jsonq); + if ( jsonp.valid === false || jsonp.value !== undefined && trusted !== true ) { + return safe.uboLog(logPrefix, 'Bad JSONPath query'); + } + const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); + const propNeedles = parsePropertiesToMatchFn(extraArgs.propsToMatch, 'url'); + self.XMLHttpRequest = class extends self.XMLHttpRequest { + open(method, url, ...args) { + const xhrDetails = { method, url }; + const matched = propNeedles.size === 0 || + matchObjectPropertiesFn(propNeedles, xhrDetails); + if ( matched ) { + if ( safe.logLevel > 1 && Array.isArray(matched) ) { + safe.uboLog(logPrefix, `Matched "propsToMatch":\n\t${matched.join('\n\t')}`); + } + xhrInstances.set(this, xhrDetails); + } + return super.open(method, url, ...args); + } + get response() { + const innerResponse = super.response; + const xhrDetails = xhrInstances.get(this); + if ( xhrDetails === undefined ) { return innerResponse; } + const responseLength = typeof innerResponse === 'string' + ? innerResponse.length + : undefined; + if ( xhrDetails.lastResponseLength !== responseLength ) { + xhrDetails.response = undefined; + xhrDetails.lastResponseLength = responseLength; + } + if ( xhrDetails.response !== undefined ) { + return xhrDetails.response; + } + let obj; + if ( typeof innerResponse === 'object' ) { + obj = innerResponse; + } else if ( typeof innerResponse === 'string' ) { + try { obj = safe.JSON_parse(innerResponse); } catch { } + } + if ( typeof obj !== 'object' || obj === null ) { + return (xhrDetails.response = innerResponse); + } + const objAfter = jsonp.apply(obj); + if ( objAfter === undefined ) { + return (xhrDetails.response = innerResponse); + } + safe.uboLog(logPrefix, 'Edited'); + const outerResponse = typeof innerResponse === 'string' + ? JSONPath.toJSON(objAfter, safe.JSON_stringify) + : objAfter; + return (xhrDetails.response = outerResponse); + } + get responseText() { + const response = this.response; + return typeof response !== 'string' + ? super.responseText + : response; + } + }; +} +registerScriptlet(jsonEditXhrResponseFn, { + name: 'json-edit-xhr-response.fn', + dependencies: [ + JSONPath, + matchObjectPropertiesFn, + parsePropertiesToMatchFn, + safeSelf, + ], +}); + +/******************************************************************************/ +/** + * @scriptlet json-edit-xhr-response.js + * + * @description + * Edit the object fetched through a XHR instance. + * Properties can only be removed. + * + * @param jsonq + * A uBO-flavored JSONPath query. + * + * @param [propsToMatch, value] + * An optional vararg detailing the arguments to match when xhr.open() is + * called. + * + * */ + +function jsonEditXhrResponse(jsonq = '', ...args) { + jsonEditXhrResponseFn(false, jsonq, ...args); +} +registerScriptlet(jsonEditXhrResponse, { + name: 'json-edit-xhr-response.js', + dependencies: [ + jsonEditXhrResponseFn, + ], +}); + +/******************************************************************************/ +/** + * @scriptlet trusted-json-edit-xhr-response.js + * + * @description + * Edit the object fetched through a XHR instance. + * Properties can be assigned new values. + * + * @param jsonq + * A uBO-flavored JSONPath query. + * + * @param [propsToMatch, value] + * An optional vararg detailing the arguments to match when xhr.open() is + * called. + * + * */ + +function trustedJsonEditXhrResponse(jsonq = '', ...args) { + jsonEditXhrResponseFn(true, jsonq, ...args); +} +registerScriptlet(trustedJsonEditXhrResponse, { + name: 'trusted-json-edit-xhr-response.js', + requiresTrust: true, + dependencies: [ + jsonEditXhrResponseFn, + ], +}); + +/******************************************************************************/ +/******************************************************************************/ + +function jsonEditXhrRequestFn(trusted, jsonq = '') { + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix( + `${trusted ? 'trusted-' : ''}json-edit-xhr-request`, + jsonq + ); + const xhrInstances = new WeakMap(); + const jsonp = JSONPath.create(jsonq); + if ( jsonp.valid === false || jsonp.value !== undefined && trusted !== true ) { + return safe.uboLog(logPrefix, 'Bad JSONPath query'); + } + const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); + const propNeedles = parsePropertiesToMatchFn(extraArgs.propsToMatch, 'url'); + self.XMLHttpRequest = class extends self.XMLHttpRequest { + open(method, url, ...args) { + const xhrDetails = { method, url }; + const matched = propNeedles.size === 0 || + matchObjectPropertiesFn(propNeedles, xhrDetails); + if ( matched ) { + if ( safe.logLevel > 1 && Array.isArray(matched) ) { + safe.uboLog(logPrefix, `Matched "propsToMatch":\n\t${matched.join('\n\t')}`); + } + xhrInstances.set(this, xhrDetails); + } + return super.open(method, url, ...args); + } + send(body) { + const xhrDetails = xhrInstances.get(this); + if ( xhrDetails ) { + body = this.#filterBody(body) || body; + } + super.send(body); + } + #filterBody(body) { + if ( typeof body !== 'string' ) { return; } + let data; + try { data = safe.JSON_parse(body); } + catch { } + if ( data instanceof Object === false ) { return; } + const objAfter = jsonp.apply(data); + if ( objAfter === undefined ) { return; } + body = safe.JSON_stringify(objAfter); + safe.uboLog(logPrefix, 'Edited'); + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `After edit:\n${body}`); + } + return body; + } + }; +} +registerScriptlet(jsonEditXhrRequestFn, { + name: 'json-edit-xhr-request.fn', + dependencies: [ + JSONPath, + matchObjectPropertiesFn, + parsePropertiesToMatchFn, + safeSelf, + ], +}); + +/******************************************************************************/ +/** + * @scriptlet json-edit-xhr-request.js + * + * @description + * Edit the object sent as the body in a XHR instance. + * Properties can only be removed. + * + * @param jsonq + * A uBO-flavored JSONPath query. + * + * @param [propsToMatch, value] + * An optional vararg detailing the arguments to match when xhr.open() is + * called. + * + * */ + +function jsonEditXhrRequest(jsonq = '', ...args) { + jsonEditXhrRequestFn(false, jsonq, ...args); +} +registerScriptlet(jsonEditXhrRequest, { + name: 'json-edit-xhr-request.js', + dependencies: [ + jsonEditXhrRequestFn, + ], +}); + +/******************************************************************************/ +/** + * @scriptlet trusted-json-edit-xhr-request.js + * + * @description + * Edit the object sent as the body in a XHR instance. + * Properties can be assigned new values. + * + * @param jsonq + * A uBO-flavored JSONPath query. + * + * @param [propsToMatch, value] + * An optional vararg detailing the arguments to match when xhr.open() is + * called. + * + * */ + +function trustedJsonEditXhrRequest(jsonq = '', ...args) { + jsonEditXhrRequestFn(true, jsonq, ...args); +} +registerScriptlet(trustedJsonEditXhrRequest, { + name: 'trusted-json-edit-xhr-request.js', + requiresTrust: true, + dependencies: [ + jsonEditXhrRequestFn, + ], +}); + +/******************************************************************************/ +/******************************************************************************/ + +function jsonEditFetchResponseFn(trusted, jsonq = '') { + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix( + `${trusted ? 'trusted-' : ''}json-edit-fetch-response`, + jsonq + ); + const jsonp = JSONPath.create(jsonq); + if ( jsonp.valid === false || jsonp.value !== undefined && trusted !== true ) { + return safe.uboLog(logPrefix, 'Bad JSONPath query'); + } + const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); + const propNeedles = parsePropertiesToMatchFn(extraArgs.propsToMatch, 'url'); + proxyApplyFn('fetch', function(context) { + const args = context.callArgs; + const fetchPromise = context.reflect(); + if ( propNeedles.size !== 0 ) { + const objs = [ args[0] instanceof Object ? args[0] : { url: args[0] } ]; + if ( objs[0] instanceof Request ) { + try { + objs[0] = safe.Request_clone.call(objs[0]); + } catch(ex) { + safe.uboErr(logPrefix, 'Error:', ex); + } + } + if ( args[1] instanceof Object ) { + objs.push(args[1]); + } + const matched = matchObjectPropertiesFn(propNeedles, ...objs); + if ( matched === undefined ) { return fetchPromise; } + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `Matched "propsToMatch":\n\t${matched.join('\n\t')}`); + } + } + return fetchPromise.then(responseBefore => { + const response = responseBefore.clone(); + return response.json().then(obj => { + if ( typeof obj !== 'object' ) { return responseBefore; } + const objAfter = jsonp.apply(obj); + if ( objAfter === undefined ) { return responseBefore; } + safe.uboLog(logPrefix, 'Edited'); + const responseAfter = Response.json(objAfter, { + status: responseBefore.status, + statusText: responseBefore.statusText, + headers: responseBefore.headers, + }); + Object.defineProperties(responseAfter, { + ok: { value: responseBefore.ok }, + redirected: { value: responseBefore.redirected }, + type: { value: responseBefore.type }, + url: { value: responseBefore.url }, + }); + return responseAfter; + }).catch(reason => { + safe.uboErr(logPrefix, 'Error:', reason); + return responseBefore; + }); + }).catch(reason => { + safe.uboErr(logPrefix, 'Error:', reason); + return fetchPromise; + }); + }); +} +registerScriptlet(jsonEditFetchResponseFn, { + name: 'json-edit-fetch-response.fn', + dependencies: [ + JSONPath, + matchObjectPropertiesFn, + parsePropertiesToMatchFn, + proxyApplyFn, + safeSelf, + ], +}); + +/******************************************************************************/ +/** + * @scriptlet json-edit-fetch-response.js + * + * @description + * Edit the object fetched through the fetch API. + * Properties can only be removed. + * + * @param jsonq + * A uBO-flavored JSONPath query. + * + * @param [propsToMatch, value] + * An optional vararg detailing the arguments to match when xhr.open() is + * called. + * + * */ + +function jsonEditFetchResponse(jsonq = '', ...args) { + jsonEditFetchResponseFn(false, jsonq, ...args); +} +registerScriptlet(jsonEditFetchResponse, { + name: 'json-edit-fetch-response.js', + dependencies: [ + jsonEditFetchResponseFn, + ], +}); + +/******************************************************************************/ +/** + * @scriptlet trusted-json-edit-fetch-response.js + * + * @description + * Edit the object fetched through the fetch API. The trusted version allows + * Properties can be assigned new values. + * + * @param jsonq + * A uBO-flavored JSONPath query. + * + * @param [propsToMatch, value] + * An optional vararg detailing the arguments to match when xhr.open() is + * called. + * + * */ + +function trustedJsonEditFetchResponse(jsonq = '', ...args) { + jsonEditFetchResponseFn(true, jsonq, ...args); +} +registerScriptlet(trustedJsonEditFetchResponse, { + name: 'trusted-json-edit-fetch-response.js', + requiresTrust: true, + dependencies: [ + jsonEditFetchResponseFn, + ], +}); + +/******************************************************************************/ +/******************************************************************************/ + +function jsonEditFetchRequestFn(trusted, jsonq = '') { + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix( + `${trusted ? 'trusted-' : ''}json-edit-fetch-request`, + jsonq + ); + const jsonp = JSONPath.create(jsonq); + if ( jsonp.valid === false || jsonp.value !== undefined && trusted !== true ) { + return safe.uboLog(logPrefix, 'Bad JSONPath query'); + } + const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); + const propNeedles = parsePropertiesToMatchFn(extraArgs.propsToMatch, 'url'); + const filterBody = body => { + if ( typeof body !== 'string' ) { return; } + let data; + try { data = safe.JSON_parse(body); } + catch { } + if ( data instanceof Object === false ) { return; } + const objAfter = jsonp.apply(data); + if ( objAfter === undefined ) { return; } + return safe.JSON_stringify(objAfter); + } + const proxyHandler = context => { + const args = context.callArgs; + const [ resource, options ] = args; + const bodyBefore = options?.body; + if ( Boolean(bodyBefore) === false ) { return context.reflect(); } + const bodyAfter = filterBody(bodyBefore); + if ( bodyAfter === undefined || bodyAfter === bodyBefore ) { + return context.reflect(); + } + if ( propNeedles.size !== 0 ) { + const objs = [ + resource instanceof Object ? resource : { url: `${resource}` } + ]; + if ( objs[0] instanceof Request ) { + try { + objs[0] = safe.Request_clone.call(objs[0]); + } catch(ex) { + safe.uboErr(logPrefix, 'Error:', ex); + } + } + const matched = matchObjectPropertiesFn(propNeedles, ...objs); + if ( matched === undefined ) { return context.reflect(); } + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `Matched "propsToMatch":\n\t${matched.join('\n\t')}`); + } + } + safe.uboLog(logPrefix, 'Edited'); + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `After edit:\n${bodyAfter}`); + } + options.body = bodyAfter; + return context.reflect(); + }; + proxyApplyFn('fetch', proxyHandler); + proxyApplyFn('Request', proxyHandler); +} +registerScriptlet(jsonEditFetchRequestFn, { + name: 'json-edit-fetch-request.fn', + dependencies: [ + JSONPath, + matchObjectPropertiesFn, + parsePropertiesToMatchFn, + proxyApplyFn, + safeSelf, + ], +}); + +/******************************************************************************/ +/** + * @scriptlet json-edit-fetch-request.js + * + * @description + * Edit the request body sent through the fetch API. + * Properties can only be removed. + * + * @param jsonq + * A uBO-flavored JSONPath query. + * + * @param [propsToMatch, value] + * An optional vararg detailing the arguments to match when fetch() is called. + * + * */ + +function jsonEditFetchRequest(jsonq = '', ...args) { + jsonEditFetchRequestFn(false, jsonq, ...args); +} +registerScriptlet(jsonEditFetchRequest, { + name: 'json-edit-fetch-request.js', + dependencies: [ + jsonEditFetchRequestFn, + ], +}); + +/******************************************************************************/ +/** + * @scriptlet trusted-json-edit-fetch-request.js + * + * @description + * Edit the request body sent through the fetch API. + * Properties can be assigned new values. + * + * @param jsonq + * A uBO-flavored JSONPath query. + * + * @param [propsToMatch, value] + * An optional vararg detailing the arguments to match when fetch() is called. + * + * */ + +function trustedJsonEditFetchRequest(jsonq = '', ...args) { + jsonEditFetchRequestFn(true, jsonq, ...args); +} +registerScriptlet(trustedJsonEditFetchRequest, { + name: 'trusted-json-edit-fetch-request.js', + requiresTrust: true, + dependencies: [ + jsonEditFetchRequestFn, + ], +}); + +/******************************************************************************/ +/******************************************************************************/ + +function jsonlEditFn(jsonp, text = '') { + const safe = safeSelf(); + const lineSeparator = /\r?\n/.exec(text)?.[0] || '\n'; + const linesBefore = text.split('\n'); + const linesAfter = []; + for ( const lineBefore of linesBefore ) { + let obj; + try { obj = safe.JSON_parse(lineBefore); } catch { } + if ( typeof obj !== 'object' || obj === null ) { + linesAfter.push(lineBefore); + continue; + } + const objAfter = jsonp.apply(obj); + if ( objAfter === undefined ) { + linesAfter.push(lineBefore); + continue; + } + const lineAfter = safe.JSON_stringify(objAfter); + linesAfter.push(lineAfter); + } + return linesAfter.join(lineSeparator); +} +registerScriptlet(jsonlEditFn, { + name: 'jsonl-edit.fn', + dependencies: [ + JSONPath, + safeSelf, + ], +}); + +/******************************************************************************/ + +function jsonlEditXhrResponseFn(trusted, jsonq = '') { + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix( + `${trusted ? 'trusted-' : ''}jsonl-edit-xhr-response`, + jsonq + ); + const xhrInstances = new WeakMap(); + const jsonp = JSONPath.create(jsonq); + if ( jsonp.valid === false || jsonp.value !== undefined && trusted !== true ) { + return safe.uboLog(logPrefix, 'Bad JSONPath query'); + } + const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); + const propNeedles = parsePropertiesToMatchFn(extraArgs.propsToMatch, 'url'); + self.XMLHttpRequest = class extends self.XMLHttpRequest { + open(method, url, ...args) { + const xhrDetails = { method, url }; + const matched = propNeedles.size === 0 || + matchObjectPropertiesFn(propNeedles, xhrDetails); + if ( matched ) { + if ( safe.logLevel > 1 && Array.isArray(matched) ) { + safe.uboLog(logPrefix, `Matched "propsToMatch":\n\t${matched.join('\n\t')}`); + } + xhrInstances.set(this, xhrDetails); + } + return super.open(method, url, ...args); + } + get response() { + const innerResponse = super.response; + const xhrDetails = xhrInstances.get(this); + if ( xhrDetails === undefined ) { + return innerResponse; + } + const responseLength = typeof innerResponse === 'string' + ? innerResponse.length + : undefined; + if ( xhrDetails.lastResponseLength !== responseLength ) { + xhrDetails.response = undefined; + xhrDetails.lastResponseLength = responseLength; + } + if ( xhrDetails.response !== undefined ) { + return xhrDetails.response; + } + if ( typeof innerResponse !== 'string' ) { + return (xhrDetails.response = innerResponse); + } + const outerResponse = jsonlEditFn(jsonp, innerResponse); + if ( outerResponse !== innerResponse ) { + safe.uboLog(logPrefix, 'Pruned'); + } + return (xhrDetails.response = outerResponse); + } + get responseText() { + const response = this.response; + return typeof response !== 'string' + ? super.responseText + : response; + } + }; +} +registerScriptlet(jsonlEditXhrResponseFn, { + name: 'jsonl-edit-xhr-response.fn', + dependencies: [ + JSONPath, + jsonlEditFn, + matchObjectPropertiesFn, + parsePropertiesToMatchFn, + safeSelf, + ], +}); + +/******************************************************************************/ +/** + * @scriptlet jsonl-edit-xhr-response.js + * + * @description + * Edit the objects found in a JSONL resource fetched through a XHR instance. + * Properties can only be removed. + * + * @param jsonq + * A uBO-flavored JSONPath query. + * + * @param [propsToMatch, value] + * An optional vararg detailing the arguments to match when xhr.open() is + * called. + * + * */ + +function jsonlEditXhrResponse(jsonq = '', ...args) { + jsonlEditXhrResponseFn(false, jsonq, ...args); +} +registerScriptlet(jsonlEditXhrResponse, { + name: 'jsonl-edit-xhr-response.js', + dependencies: [ + jsonlEditXhrResponseFn, + ], +}); + +/******************************************************************************/ +/** + * @scriptlet trusted-jsonl-edit-xhr-response.js + * + * @description + * Edit the objects found in a JSONL resource fetched through a XHR instance. + * Properties can be assigned new values. + * + * @param jsonq + * A uBO-flavored JSONPath query. + * + * @param [propsToMatch, value] + * An optional vararg detailing the arguments to match when xhr.open() is + * called. + * + * */ + +function trustedJsonlEditXhrResponse(jsonq = '', ...args) { + jsonlEditXhrResponseFn(true, jsonq, ...args); +} +registerScriptlet(trustedJsonlEditXhrResponse, { + name: 'trusted-jsonl-edit-xhr-response.js', + requiresTrust: true, + dependencies: [ + jsonlEditXhrResponseFn, + ], +}); + +/******************************************************************************/ +/******************************************************************************/ + +function jsonlEditFetchResponseFn(trusted, jsonq = '') { + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix( + `${trusted ? 'trusted-' : ''}jsonl-edit-fetch-response`, + jsonq + ); + const jsonp = JSONPath.create(jsonq); + if ( jsonp.valid === false || jsonp.value !== undefined && trusted !== true ) { + return safe.uboLog(logPrefix, 'Bad JSONPath query'); + } + const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); + const propNeedles = parsePropertiesToMatchFn(extraArgs.propsToMatch, 'url'); + const logall = jsonq === ''; + proxyApplyFn('fetch', function(context) { + const args = context.callArgs; + const fetchPromise = context.reflect(); + if ( propNeedles.size !== 0 ) { + const objs = [ args[0] instanceof Object ? args[0] : { url: args[0] } ]; + if ( objs[0] instanceof Request ) { + try { + objs[0] = safe.Request_clone.call(objs[0]); + } catch(ex) { + safe.uboErr(logPrefix, 'Error:', ex); + } + } + if ( args[1] instanceof Object ) { + objs.push(args[1]); + } + const matched = matchObjectPropertiesFn(propNeedles, ...objs); + if ( matched === undefined ) { return fetchPromise; } + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `Matched "propsToMatch":\n\t${matched.join('\n\t')}`); + } + } + return fetchPromise.then(responseBefore => { + const response = responseBefore.clone(); + return response.text().then(textBefore => { + if ( typeof textBefore !== 'string' ) { return textBefore; } + if ( logall ) { + safe.uboLog(logPrefix, textBefore); + return responseBefore; + } + const textAfter = jsonlEditFn(jsonp, textBefore); + if ( textAfter === textBefore ) { return responseBefore; } + safe.uboLog(logPrefix, 'Pruned'); + const responseAfter = new Response(textAfter, { + status: responseBefore.status, + statusText: responseBefore.statusText, + headers: responseBefore.headers, + }); + Object.defineProperties(responseAfter, { + ok: { value: responseBefore.ok }, + redirected: { value: responseBefore.redirected }, + type: { value: responseBefore.type }, + url: { value: responseBefore.url }, + }); + return responseAfter; + }).catch(reason => { + safe.uboErr(logPrefix, 'Error:', reason); + return responseBefore; + }); + }).catch(reason => { + safe.uboErr(logPrefix, 'Error:', reason); + return fetchPromise; + }); + }); +} +registerScriptlet(jsonlEditFetchResponseFn, { + name: 'jsonl-edit-fetch-response.fn', + dependencies: [ + JSONPath, + jsonlEditFn, + matchObjectPropertiesFn, + parsePropertiesToMatchFn, + proxyApplyFn, + safeSelf, + ], +}); + +/******************************************************************************/ +/** + * @scriptlet jsonl-edit-fetch-response.js + * + * @description + * Edit the objects found in a JSONL resource fetched through the fetch API. + * Properties can only be removed. + * + * @param jsonq + * A uBO-flavored JSONPath query. + * + * @param [propsToMatch, value] + * An optional vararg detailing the arguments to match when xhr.open() is + * called. + * + * */ + +function jsonlEditFetchResponse(jsonq = '', ...args) { + jsonlEditFetchResponseFn(false, jsonq, ...args); +} +registerScriptlet(jsonlEditFetchResponse, { + name: 'jsonl-edit-fetch-response.js', + dependencies: [ + jsonlEditFetchResponseFn, + ], +}); + +/******************************************************************************/ +/** + * @scriptlet trusted-jsonl-edit-fetch-response.js + * + * @description + * Edit the objects found in a JSONL resource fetched through the fetch API. + * Properties can be assigned new values. + * + * @param jsonq + * A uBO-flavored JSONPath query. + * + * @param [propsToMatch, value] + * An optional vararg detailing the arguments to match when xhr.open() is + * called. + * + * */ + +function trustedJsonlEditFetchResponse(jsonq = '', ...args) { + jsonlEditFetchResponseFn(true, jsonq, ...args); +} +registerScriptlet(trustedJsonlEditFetchResponse, { + name: 'trusted-jsonl-edit-fetch-response.js', + requiresTrust: true, + dependencies: [ + jsonlEditFetchResponseFn, + ], +}); + +/******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/json-prune.js ublock-origin-1.67.0+dfsg/src/js/resources/json-prune.js --- ublock-origin-1.62.0+dfsg/src/js/resources/json-prune.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/json-prune.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,275 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2019-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock + +*/ + +import { + matchObjectPropertiesFn, + parsePropertiesToMatchFn, +} from './utils.js'; + +import { objectPruneFn } from './object-prune.js'; +import { proxyApplyFn } from './proxy-apply.js'; +import { registerScriptlet } from './base.js'; +import { safeSelf } from './safe-self.js'; + +/******************************************************************************/ + +function jsonPrune( + rawPrunePaths = '', + rawNeedlePaths = '', + stackNeedle = '' +) { + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('json-prune', rawPrunePaths, rawNeedlePaths, stackNeedle); + const stackNeedleDetails = safe.initPattern(stackNeedle, { canNegate: true }); + const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); + JSON.parse = new Proxy(JSON.parse, { + apply: function(target, thisArg, args) { + const objBefore = Reflect.apply(target, thisArg, args); + if ( rawPrunePaths === '' ) { + safe.uboLog(logPrefix, safe.JSON_stringify(objBefore, null, 2)); + } + const objAfter = objectPruneFn( + objBefore, + rawPrunePaths, + rawNeedlePaths, + stackNeedleDetails, + extraArgs + ); + if ( objAfter === undefined ) { return objBefore; } + safe.uboLog(logPrefix, 'Pruned'); + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `After pruning:\n${safe.JSON_stringify(objAfter, null, 2)}`); + } + return objAfter; + }, + }); +} +registerScriptlet(jsonPrune, { + name: 'json-prune.js', + dependencies: [ + objectPruneFn, + safeSelf, + ], +}); + +/******************************************************************************/ + +function jsonPruneFetchResponse( + rawPrunePaths = '', + rawNeedlePaths = '' +) { + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('json-prune-fetch-response', rawPrunePaths, rawNeedlePaths); + const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); + const propNeedles = parsePropertiesToMatchFn(extraArgs.propsToMatch, 'url'); + const stackNeedle = safe.initPattern(extraArgs.stackToMatch || '', { canNegate: true }); + const logall = rawPrunePaths === ''; + const applyHandler = function(target, thisArg, args) { + const fetchPromise = Reflect.apply(target, thisArg, args); + if ( propNeedles.size !== 0 ) { + const objs = [ args[0] instanceof Object ? args[0] : { url: args[0] } ]; + if ( objs[0] instanceof Request ) { + try { + objs[0] = safe.Request_clone.call(objs[0]); + } catch(ex) { + safe.uboErr(logPrefix, 'Error:', ex); + } + } + if ( args[1] instanceof Object ) { + objs.push(args[1]); + } + const matched = matchObjectPropertiesFn(propNeedles, ...objs); + if ( matched === undefined ) { return fetchPromise; } + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `Matched "propsToMatch":\n\t${matched.join('\n\t')}`); + } + } + return fetchPromise.then(responseBefore => { + const response = responseBefore.clone(); + return response.json().then(objBefore => { + if ( typeof objBefore !== 'object' ) { return responseBefore; } + if ( logall ) { + safe.uboLog(logPrefix, safe.JSON_stringify(objBefore, null, 2)); + return responseBefore; + } + const objAfter = objectPruneFn( + objBefore, + rawPrunePaths, + rawNeedlePaths, + stackNeedle, + extraArgs + ); + if ( typeof objAfter !== 'object' ) { return responseBefore; } + safe.uboLog(logPrefix, 'Pruned'); + const responseAfter = Response.json(objAfter, { + status: responseBefore.status, + statusText: responseBefore.statusText, + headers: responseBefore.headers, + }); + Object.defineProperties(responseAfter, { + ok: { value: responseBefore.ok }, + redirected: { value: responseBefore.redirected }, + type: { value: responseBefore.type }, + url: { value: responseBefore.url }, + }); + return responseAfter; + }).catch(reason => { + safe.uboErr(logPrefix, 'Error:', reason); + return responseBefore; + }); + }).catch(reason => { + safe.uboErr(logPrefix, 'Error:', reason); + return fetchPromise; + }); + }; + self.fetch = new Proxy(self.fetch, { + apply: applyHandler + }); +} +registerScriptlet(jsonPruneFetchResponse, { + name: 'json-prune-fetch-response.js', + dependencies: [ + matchObjectPropertiesFn, + objectPruneFn, + parsePropertiesToMatchFn, + safeSelf, + ], +}); + +/******************************************************************************/ + +function jsonPruneXhrResponse( + rawPrunePaths = '', + rawNeedlePaths = '' +) { + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('json-prune-xhr-response', rawPrunePaths, rawNeedlePaths); + const xhrInstances = new WeakMap(); + const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); + const propNeedles = parsePropertiesToMatchFn(extraArgs.propsToMatch, 'url'); + const stackNeedle = safe.initPattern(extraArgs.stackToMatch || '', { canNegate: true }); + self.XMLHttpRequest = class extends self.XMLHttpRequest { + open(method, url, ...args) { + const xhrDetails = { method, url }; + let outcome = 'match'; + if ( propNeedles.size !== 0 ) { + if ( matchObjectPropertiesFn(propNeedles, xhrDetails) === undefined ) { + outcome = 'nomatch'; + } + } + if ( outcome === 'match' ) { + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `Matched optional "propsToMatch", "${extraArgs.propsToMatch}"`); + } + xhrInstances.set(this, xhrDetails); + } + return super.open(method, url, ...args); + } + get response() { + const innerResponse = super.response; + const xhrDetails = xhrInstances.get(this); + if ( xhrDetails === undefined ) { + return innerResponse; + } + const responseLength = typeof innerResponse === 'string' + ? innerResponse.length + : undefined; + if ( xhrDetails.lastResponseLength !== responseLength ) { + xhrDetails.response = undefined; + xhrDetails.lastResponseLength = responseLength; + } + if ( xhrDetails.response !== undefined ) { + return xhrDetails.response; + } + let objBefore; + if ( typeof innerResponse === 'object' ) { + objBefore = innerResponse; + } else if ( typeof innerResponse === 'string' ) { + try { + objBefore = safe.JSON_parse(innerResponse); + } catch { + } + } + if ( typeof objBefore !== 'object' ) { + return (xhrDetails.response = innerResponse); + } + const objAfter = objectPruneFn( + objBefore, + rawPrunePaths, + rawNeedlePaths, + stackNeedle, + extraArgs + ); + let outerResponse; + if ( typeof objAfter === 'object' ) { + outerResponse = typeof innerResponse === 'string' + ? safe.JSON_stringify(objAfter) + : objAfter; + safe.uboLog(logPrefix, 'Pruned'); + } else { + outerResponse = innerResponse; + } + return (xhrDetails.response = outerResponse); + } + get responseText() { + const response = this.response; + return typeof response !== 'string' + ? super.responseText + : response; + } + }; +} +registerScriptlet(jsonPruneXhrResponse, { + name: 'json-prune-xhr-response.js', + dependencies: [ + matchObjectPropertiesFn, + objectPruneFn, + parsePropertiesToMatchFn, + safeSelf, + ], +}); + +/******************************************************************************/ + +// There is still code out there which uses `eval` in lieu of `JSON.parse`. + +function evaldataPrune( + rawPrunePaths = '', + rawNeedlePaths = '' +) { + proxyApplyFn('eval', function(context) { + const before = context.reflect(); + if ( typeof before !== 'object' ) { return before; } + if ( before === null ) { return null; } + const after = objectPruneFn(before, rawPrunePaths, rawNeedlePaths); + return after || before; + }); +} +registerScriptlet(evaldataPrune, { + name: 'evaldata-prune.js', + dependencies: [ + objectPruneFn, + proxyApplyFn, + ], +}); + +/******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/localstorage.js ublock-origin-1.67.0+dfsg/src/js/resources/localstorage.js --- ublock-origin-1.62.0+dfsg/src/js/resources/localstorage.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/localstorage.js 2025-10-25 19:32:51.000000000 +0000 @@ -102,7 +102,7 @@ } else { storage.setItem(key, `${value}`); } - } catch(ex) { + } catch { } } registerScriptlet(setLocalStorageItemFn, { diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/noeval.js ublock-origin-1.67.0+dfsg/src/js/resources/noeval.js --- ublock-origin-1.62.0+dfsg/src/js/resources/noeval.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/noeval.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,58 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2019-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock + +*/ + +import { proxyApplyFn } from './proxy-apply.js'; +import { registerScriptlet } from './base.js'; +import { safeSelf } from './safe-self.js'; + +/******************************************************************************/ + +function noEvalIf( + needle = '' +) { + if ( typeof needle !== 'string' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('noeval-if', needle); + const reNeedle = safe.patternToRegex(needle); + proxyApplyFn('eval', function(context) { + const { callArgs } = context; + const a = String(callArgs[0]); + if ( needle !== '' && reNeedle.test(a) ) { + safe.uboLog(logPrefix, 'Prevented:\n', a); + return; + } + if ( needle === '' || safe.logLevel > 1 ) { + safe.uboLog(logPrefix, 'Not prevented:\n', a); + } + return context.reflect(); + }); +} +registerScriptlet(noEvalIf, { + name: 'noeval-if.js', + aliases: [ + 'prevent-eval-if.js', + ], + dependencies: [ + proxyApplyFn, + safeSelf, + ], +}); diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/object-prune.js ublock-origin-1.67.0+dfsg/src/js/resources/object-prune.js --- ublock-origin-1.62.0+dfsg/src/js/resources/object-prune.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/object-prune.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,272 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2019-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock + +*/ + +import { matchesStackTraceFn } from './stack-trace.js'; +import { proxyApplyFn } from './proxy-apply.js'; +import { registerScriptlet } from './base.js'; +import { safeSelf } from './safe-self.js'; + +/******************************************************************************/ + +function objectFindOwnerFn( + root, + path, + prune = false +) { + const safe = safeSelf(); + let owner = root; + let chain = path; + for (;;) { + if ( typeof owner !== 'object' || owner === null ) { return false; } + const pos = chain.indexOf('.'); + if ( pos === -1 ) { + if ( prune === false ) { + return safe.Object_hasOwn(owner, chain); + } + let modified = false; + if ( chain === '*' ) { + for ( const key in owner ) { + if ( safe.Object_hasOwn(owner, key) === false ) { continue; } + delete owner[key]; + modified = true; + } + } else if ( safe.Object_hasOwn(owner, chain) ) { + delete owner[chain]; + modified = true; + } + return modified; + } + const prop = chain.slice(0, pos); + const next = chain.slice(pos + 1); + let found = false; + if ( prop === '[-]' && Array.isArray(owner) ) { + let i = owner.length; + while ( i-- ) { + if ( objectFindOwnerFn(owner[i], next) === false ) { continue; } + owner.splice(i, 1); + found = true; + } + return found; + } + if ( prop === '{-}' && owner instanceof Object ) { + for ( const key of Object.keys(owner) ) { + if ( objectFindOwnerFn(owner[key], next) === false ) { continue; } + delete owner[key]; + found = true; + } + return found; + } + if ( + prop === '[]' && Array.isArray(owner) || + prop === '{}' && owner instanceof Object || + prop === '*' && owner instanceof Object + ) { + for ( const key of Object.keys(owner) ) { + if (objectFindOwnerFn(owner[key], next, prune) === false ) { continue; } + found = true; + } + return found; + } + if ( safe.Object_hasOwn(owner, prop) === false ) { return false; } + owner = owner[prop]; + chain = chain.slice(pos + 1); + } +} +registerScriptlet(objectFindOwnerFn, { + name: 'object-find-owner.fn', + dependencies: [ + safeSelf, + ], +}); + +/******************************************************************************/ + +// When no "prune paths" argument is provided, the scriptlet is +// used for logging purpose and the "needle paths" argument is +// used to filter logging output. +// +// https://github.com/uBlockOrigin/uBlock-issues/issues/1545 +// - Add support for "remove everything if needle matches" case + +export function objectPruneFn( + obj, + rawPrunePaths, + rawNeedlePaths, + stackNeedleDetails = { matchAll: true }, + extraArgs = {} +) { + if ( typeof rawPrunePaths !== 'string' ) { return; } + const safe = safeSelf(); + const prunePaths = rawPrunePaths !== '' + ? safe.String_split.call(rawPrunePaths, / +/) + : []; + const needlePaths = prunePaths.length !== 0 && rawNeedlePaths !== '' + ? safe.String_split.call(rawNeedlePaths, / +/) + : []; + if ( stackNeedleDetails.matchAll !== true ) { + if ( matchesStackTraceFn(stackNeedleDetails, extraArgs.logstack) === false ) { + return; + } + } + if ( objectPruneFn.mustProcess === undefined ) { + objectPruneFn.mustProcess = (root, needlePaths) => { + for ( const needlePath of needlePaths ) { + if ( objectFindOwnerFn(root, needlePath) === false ) { + return false; + } + } + return true; + }; + } + if ( prunePaths.length === 0 ) { return; } + let outcome = 'nomatch'; + if ( objectPruneFn.mustProcess(obj, needlePaths) ) { + for ( const path of prunePaths ) { + if ( objectFindOwnerFn(obj, path, true) ) { + outcome = 'match'; + } + } + } + if ( outcome === 'match' ) { return obj; } +} +registerScriptlet(objectPruneFn, { + name: 'object-prune.fn', + dependencies: [ + matchesStackTraceFn, + objectFindOwnerFn, + safeSelf, + ], +}); + +/******************************************************************************/ + +function trustedPruneInboundObject( + entryPoint = '', + argPos = '', + rawPrunePaths = '', + rawNeedlePaths = '' +) { + if ( entryPoint === '' ) { return; } + let context = globalThis; + let prop = entryPoint; + for (;;) { + const pos = prop.indexOf('.'); + if ( pos === -1 ) { break; } + context = context[prop.slice(0, pos)]; + if ( context instanceof Object === false ) { return; } + prop = prop.slice(pos+1); + } + if ( typeof context[prop] !== 'function' ) { return; } + const argIndex = parseInt(argPos); + if ( isNaN(argIndex) ) { return; } + if ( argIndex < 1 ) { return; } + const safe = safeSelf(); + const extraArgs = safe.getExtraArgs(Array.from(arguments), 4); + const needlePaths = []; + if ( rawPrunePaths !== '' ) { + needlePaths.push(...safe.String_split.call(rawPrunePaths, / +/)); + } + if ( rawNeedlePaths !== '' ) { + needlePaths.push(...safe.String_split.call(rawNeedlePaths, / +/)); + } + const stackNeedle = safe.initPattern(extraArgs.stackToMatch || '', { canNegate: true }); + const mustProcess = root => { + for ( const needlePath of needlePaths ) { + if ( objectFindOwnerFn(root, needlePath) === false ) { + return false; + } + } + return true; + }; + context[prop] = new Proxy(context[prop], { + apply: function(target, thisArg, args) { + const targetArg = argIndex <= args.length + ? args[argIndex-1] + : undefined; + if ( targetArg instanceof Object && mustProcess(targetArg) ) { + let objBefore = targetArg; + if ( extraArgs.dontOverwrite ) { + try { + objBefore = safe.JSON_parse(safe.JSON_stringify(targetArg)); + } catch { + objBefore = undefined; + } + } + if ( objBefore !== undefined ) { + const objAfter = objectPruneFn( + objBefore, + rawPrunePaths, + rawNeedlePaths, + stackNeedle, + extraArgs + ); + args[argIndex-1] = objAfter || objBefore; + } + } + return Reflect.apply(target, thisArg, args); + }, + }); +} +registerScriptlet(trustedPruneInboundObject, { + name: 'trusted-prune-inbound-object.js', + requiresTrust: true, + dependencies: [ + objectFindOwnerFn, + objectPruneFn, + safeSelf, + ], +}); + +/******************************************************************************/ + +function trustedPruneOutboundObject( + propChain = '', + rawPrunePaths = '', + rawNeedlePaths = '' +) { + if ( propChain === '' ) { return; } + const safe = safeSelf(); + const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); + proxyApplyFn(propChain, function(context) { + const objBefore = context.reflect(); + if ( objBefore instanceof Object === false ) { return objBefore; } + const objAfter = objectPruneFn( + objBefore, + rawPrunePaths, + rawNeedlePaths, + { matchAll: true }, + extraArgs + ); + return objAfter || objBefore; + }); +} +registerScriptlet(trustedPruneOutboundObject, { + name: 'trusted-prune-outbound-object.js', + requiresTrust: true, + dependencies: [ + objectPruneFn, + proxyApplyFn, + safeSelf, + ], +}); + +/******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/parse-replace.js ublock-origin-1.67.0+dfsg/src/js/resources/parse-replace.js --- ublock-origin-1.62.0+dfsg/src/js/resources/parse-replace.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/parse-replace.js 2025-10-25 19:32:51.000000000 +0000 @@ -20,14 +20,14 @@ */ -import { createArglistParser } from './shared.js'; +import { ArglistParser } from './shared.js'; import { registerScriptlet } from './base.js'; /******************************************************************************/ export function parseReplaceFn(s) { if ( s.charCodeAt(0) !== 0x2F /* / */ ) { return; } - const parser = createArglistParser('/'); + const parser = new ArglistParser('/'); parser.nextArg(s, 1); let pattern = s.slice(parser.argBeg, parser.argEnd); if ( parser.transform ) { @@ -43,12 +43,12 @@ const flags = s.slice(parser.separatorEnd); try { return { re: new RegExp(pattern, flags), replacement }; - } catch(_) { + } catch { } } registerScriptlet(parseReplaceFn, { name: 'parse-replace.fn', dependencies: [ - createArglistParser, + ArglistParser, ], }); diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/prevent-fetch.js ublock-origin-1.67.0+dfsg/src/js/resources/prevent-fetch.js --- ublock-origin-1.62.0+dfsg/src/js/resources/prevent-fetch.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/prevent-fetch.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,221 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2019-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock + +*/ + +import { generateContentFn } from './utils.js'; +import { proxyApplyFn } from './proxy-apply.js'; +import { registerScriptlet } from './base.js'; +import { safeSelf } from './safe-self.js'; + +/******************************************************************************/ + +function preventFetchFn( + trusted = false, + propsToMatch = '', + responseBody = '', + responseType = '' +) { + const safe = safeSelf(); + const setTimeout = self.setTimeout; + const scriptletName = `${trusted ? 'trusted-' : ''}prevent-fetch`; + const logPrefix = safe.makeLogPrefix( + scriptletName, + propsToMatch, + responseBody, + responseType + ); + const extraArgs = safe.getExtraArgs(Array.from(arguments), 4); + const needles = []; + for ( const condition of safe.String_split.call(propsToMatch, /\s+/) ) { + if ( condition === '' ) { continue; } + const pos = condition.indexOf(':'); + let key, value; + if ( pos !== -1 ) { + key = condition.slice(0, pos); + value = condition.slice(pos + 1); + } else { + key = 'url'; + value = condition; + } + needles.push({ key, pattern: safe.initPattern(value, { canNegate: true }) }); + } + const validResponseProps = { + ok: [ false, true ], + statusText: [ '', 'Not Found' ], + type: [ 'basic', 'cors', 'default', 'error', 'opaque' ], + }; + const responseProps = { + statusText: { value: 'OK' }, + }; + if ( /^\{.*\}$/.test(responseType) ) { + try { + Object.entries(JSON.parse(responseType)).forEach(([ p, v ]) => { + if ( validResponseProps[p] === undefined ) { return; } + if ( validResponseProps[p].includes(v) === false ) { return; } + responseProps[p] = { value: v }; + }); + } + catch { } + } else if ( responseType !== '' ) { + if ( validResponseProps.type.includes(responseType) ) { + responseProps.type = { value: responseType }; + } + } + proxyApplyFn('fetch', function fetch(context) { + const { callArgs } = context; + const details = callArgs[0] instanceof self.Request + ? callArgs[0] + : Object.assign({ url: callArgs[0] }, callArgs[1]); + let proceed = true; + try { + const props = new Map(); + for ( const prop in details ) { + let v = details[prop]; + if ( typeof v !== 'string' ) { + try { v = safe.JSON_stringify(v); } + catch { } + } + if ( typeof v !== 'string' ) { continue; } + props.set(prop, v); + } + if ( safe.logLevel > 1 || propsToMatch === '' && responseBody === '' ) { + const out = Array.from(props).map(a => `${a[0]}:${a[1]}`); + safe.uboLog(logPrefix, `Called: ${out.join('\n')}`); + } + if ( propsToMatch === '' && responseBody === '' ) { + return context.reflect(); + } + proceed = needles.length === 0; + for ( const { key, pattern } of needles ) { + if ( + pattern.expect && props.has(key) === false || + safe.testPattern(pattern, props.get(key)) === false + ) { + proceed = true; + break; + } + } + } catch { + } + if ( proceed ) { + return context.reflect(); + } + return Promise.resolve(generateContentFn(trusted, responseBody)).then(text => { + safe.uboLog(logPrefix, `Prevented with response "${text}"`); + const response = new Response(text, { + headers: { + 'Content-Length': text.length, + } + }); + const props = Object.assign( + { url: { value: details.url } }, + responseProps + ); + safe.Object_defineProperties(response, props); + if ( extraArgs.throttle ) { + return new Promise(resolve => { + setTimeout(( ) => { resolve(response); }, extraArgs.throttle); + }); + } + return response; + }); + }); +} +registerScriptlet(preventFetchFn, { + name: 'prevent-fetch.fn', + dependencies: [ + generateContentFn, + proxyApplyFn, + safeSelf, + ], +}); + +/******************************************************************************/ +/** + * @scriptlet prevent-fetch + * + * @description + * Prevent a fetch() call from making a network request to a remote server. + * + * @param propsToMatch + * The fetch arguments to match for the prevention to be triggered. The + * untrusted flavor limits the realm of response to return to safe values. + * + * @param [responseBody] + * Optional. The reponse to return when the prevention occurs. + * + * @param [responseType] + * Optional. The response type to use when emitting a dummy response as a + * result of the prevention. + * + * @param [...varargs] + * ["throttle", n]: the time to wait in ms before returning a result. + * + * */ + +function preventFetch(...args) { + preventFetchFn(false, ...args); +} +registerScriptlet(preventFetch, { + name: 'prevent-fetch.js', + aliases: [ + 'no-fetch-if.js', + ], + dependencies: [ + preventFetchFn, + ], +}); + +/******************************************************************************/ +/** + * @scriptlet trusted-prevent-fetch + * + * @description + * Prevent a fetch() call from making a network request to a remote server. + * + * @param propsToMatch + * The fetch arguments to match for the prevention to be triggered. + * + * @param [responseBody] + * Optional. The reponse to return when the prevention occurs. The trusted + * flavor allows to return any response. + * + * @param [responseType] + * Optional. The response type to use when emitting a dummy response as a + * result of the prevention. + * + * @param [...varargs] + * ["throttle", n]: the time to wait in ms before returning a result. + * + * */ + +function trustedPreventFetch(...args) { + preventFetchFn(true, ...args); +} +registerScriptlet(trustedPreventFetch, { + name: 'trusted-prevent-fetch.js', + requiresTrust: true, + dependencies: [ + preventFetchFn, + ], +}); + +/******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/prevent-innerHTML.js ublock-origin-1.67.0+dfsg/src/js/resources/prevent-innerHTML.js --- ublock-origin-1.62.0+dfsg/src/js/resources/prevent-innerHTML.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/prevent-innerHTML.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,82 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock + +*/ + +import { registerScriptlet } from './base.js'; +import { safeSelf } from './safe-self.js'; + +/** + * @scriptlet prevent-innerHTML + * + * @description + * Conditionally prevent assignment to `innerHTML` property. + * + * @param [selector] + * Optional. The element must matches `selector` for the prevention to take + * place. + * + * @param [pattern] + * Optional. A pattern to match against the assigned value. The pattern can be + * a plain string, or a regex. Prepend with `!` to reverse the match condition. + * + * */ + +export function preventInnerHTML( + selector = '', + pattern = '' +) { + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('prevent-innerHTML', selector, pattern); + const matcher = safe.initPattern(pattern, { canNegate: true }); + const current = safe.Object_getOwnPropertyDescriptor(Element.prototype, 'innerHTML'); + if ( current === undefined ) { return; } + const shouldPreventSet = (elem, a) => { + if ( selector !== '' ) { + if ( typeof elem.matches !== 'function' ) { return false; } + if ( elem.matches(selector) === false ) { return false; } + } + return safe.testPattern(matcher, `${a}`); + }; + Object.defineProperty(Element.prototype, 'innerHTML', { + get: function() { + return current.get + ? current.get.call(this) + : current.value; + }, + set: function(a) { + if ( shouldPreventSet(this, a) ) { + safe.uboLog(logPrefix, 'Prevented'); + } else if ( current.set ) { + current.set.call(this, a); + } + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `Assigned:\n${a}`); + } + current.value = a; + }, + }); +} +registerScriptlet(preventInnerHTML, { + name: 'prevent-innerHTML.js', + dependencies: [ + safeSelf, + ], +}); diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/prevent-settimeout.js ublock-origin-1.67.0+dfsg/src/js/resources/prevent-settimeout.js --- ublock-origin-1.62.0+dfsg/src/js/resources/prevent-settimeout.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/prevent-settimeout.js 2025-10-25 19:32:51.000000000 +0000 @@ -36,7 +36,7 @@ this.min = this.max = parseInt(s, 10) || 0; } if ( pos !== -1 ) { - this.max = parseInt(s.slice(1), 10) || Number.MAX_SAFE_INTEGER; + this.max = parseInt(s.slice(pos + 1), 10) || Number.MAX_SAFE_INTEGER; } } unbound() { @@ -95,8 +95,8 @@ proxyApplyFn('setTimeout', function(context) { const { callArgs } = context; const a = callArgs[0] instanceof Function - ? String(safe.Function_toString(callArgs[0])) - : String(callArgs[0]); + ? safe.String(safe.Function_toString(callArgs[0])) + : safe.String(callArgs[0]); const b = callArgs[1]; if ( needleRaw === '' && range.unbound() ) { safe.uboLog(logPrefix, `Called:\n${a}\n${b}`); @@ -159,8 +159,8 @@ proxyApplyFn('setInterval', function(context) { const { callArgs } = context; const a = callArgs[0] instanceof Function - ? String(safe.Function_toString(callArgs[0])) - : String(callArgs[0]); + ? safe.String(safe.Function_toString(callArgs[0])) + : safe.String(callArgs[0]); const b = callArgs[1]; if ( needleRaw === '' && range.unbound() ) { safe.uboLog(logPrefix, `Called:\n${a}\n${b}`); @@ -212,8 +212,8 @@ proxyApplyFn('requestAnimationFrame', function(context) { const { callArgs } = context; const a = callArgs[0] instanceof Function - ? String(safe.Function_toString(callArgs[0])) - : String(callArgs[0]); + ? safe.String(safe.Function_toString(callArgs[0])) + : safe.String(callArgs[0]); if ( needleRaw === '' ) { safe.uboLog(logPrefix, `Called:\n${a}`); } else if ( reNeedle.test(a) !== needleNot ) { diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/proxy-apply.js ublock-origin-1.67.0+dfsg/src/js/resources/proxy-apply.js --- ublock-origin-1.62.0+dfsg/src/js/resources/proxy-apply.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/proxy-apply.js 2025-10-25 19:32:51.000000000 +0000 @@ -85,6 +85,10 @@ : new proxyApplyFn.ApplyContext(...args); } }; + proxyApplyFn.isCtor = new Map(); + } + if ( proxyApplyFn.isCtor.has(target) === false ) { + proxyApplyFn.isCtor.set(target, fn.prototype?.constructor === fn); } const fnStr = fn.toString(); const toString = (function toString() { return fnStr; }).bind(null); @@ -97,7 +101,7 @@ return Reflect.get(target, prop); }, }; - if ( fn.prototype?.constructor === fn ) { + if ( proxyApplyFn.isCtor.get(target) ) { proxyDetails.construct = function(target, args) { return handler(proxyApplyFn.CtorContext.factory(target, args)); }; diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/replace-argument.js ublock-origin-1.67.0+dfsg/src/js/resources/replace-argument.js --- ublock-origin-1.62.0+dfsg/src/js/resources/replace-argument.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/replace-argument.js 2025-10-25 19:32:51.000000000 +0000 @@ -48,6 +48,8 @@ * json-parsed string after `json:`. * If the replacement value matches `repl:/.../.../`, the target argument will * be replaced according the regex-replacement directive following `repl:` + * If the replacement value matches `add:number`, number will be added to the + * target argument. * * @param [, condition, pattern] * Optional. The replacement will occur only when pattern matches the target @@ -65,10 +67,19 @@ const logPrefix = safe.makeLogPrefix('trusted-replace-argument', propChain, argposRaw, argraw); const argoffset = parseInt(argposRaw, 10) || 0; const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); - const replacer = argraw.startsWith('repl:/') && - parseReplaceFn(argraw.slice(5)) || undefined; - const value = replacer === undefined && - validateConstantFn(true, argraw, extraArgs) || undefined; + let replacer; + if ( argraw.startsWith('repl:/') ) { + const parsed = parseReplaceFn(argraw.slice(5)); + if ( parsed === undefined ) { return; } + replacer = arg => `${arg}`.replace(replacer.re, replacer.replacement); + } else if ( argraw.startsWith('add:') ) { + const delta = parseFloat(argraw.slice(4)); + if ( isNaN(delta) ) { return; } + replacer = arg => Number(arg) + delta; + } else { + const value = validateConstantFn(true, argraw, extraArgs); + replacer = ( ) => value; + } const reCondition = extraArgs.condition ? safe.patternToRegex(extraArgs.condition) : /^/; @@ -95,12 +106,12 @@ return context.reflect(); } const argBefore = getArg(context); - if ( safe.RegExp_test.call(reCondition, argBefore) === false ) { - return context.reflect(); + if ( extraArgs.condition !== undefined ) { + if ( safe.RegExp_test.call(reCondition, argBefore) === false ) { + return context.reflect(); + } } - const argAfter = replacer && typeof argBefore === 'string' - ? argBefore.replace(replacer.re, replacer.replacement) - : value; + const argAfter = replacer(argBefore); if ( argAfter !== argBefore ) { setArg(context, argAfter); safe.uboLog(logPrefix, `Replaced argument:\nBefore: ${JSON.stringify(argBefore)}\nAfter: ${argAfter}`); diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/run-at.js ublock-origin-1.67.0+dfsg/src/js/resources/run-at.js --- ublock-origin-1.62.0+dfsg/src/js/resources/run-at.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/run-at.js 2025-10-25 19:32:51.000000000 +0000 @@ -53,7 +53,7 @@ const tokens = Array.isArray(state) ? state : [ state ]; for ( const token of tokens ) { const prop = `${token}`; - if ( targets.hasOwnProperty(prop) === false ) { continue; } + if ( Object.hasOwn(targets, prop) === false ) { continue; } return targets[prop]; } return 0; diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/safe-self.js ublock-origin-1.67.0+dfsg/src/js/resources/safe-self.js --- ublock-origin-1.62.0+dfsg/src/js/resources/safe-self.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/safe-self.js 2025-10-25 19:32:51.000000000 +0000 @@ -46,10 +46,12 @@ 'Object_defineProperties': Object.defineProperties.bind(Object), 'Object_fromEntries': Object.fromEntries.bind(Object), 'Object_getOwnPropertyDescriptor': Object.getOwnPropertyDescriptor.bind(Object), + 'Object_hasOwn': Object.hasOwn.bind(Object), 'RegExp': self.RegExp, 'RegExp_test': self.RegExp.prototype.test, 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, + 'String': self.String, 'String_fromCharCode': String.fromCharCode, 'String_split': String.prototype.split, 'XMLHttpRequest': self.XMLHttpRequest, @@ -127,7 +129,7 @@ try { return new RegExp(match[1], match[2] || undefined); } - catch(ex) { + catch { } return /^/; }, @@ -205,7 +207,7 @@ } }; bc.postMessage('areyouready?'); - } catch(_) { + } catch { safe.sendToLogger = (type, ...args) => { const text = safe.toLogText(type, ...args); if ( text === undefined ) { return; } diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/scriptlets.js ublock-origin-1.67.0+dfsg/src/js/resources/scriptlets.js --- ublock-origin-1.62.0+dfsg/src/js/resources/scriptlets.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/scriptlets.js 2025-10-25 19:32:51.000000000 +0000 @@ -21,15 +21,30 @@ */ import './attribute.js'; +import './create-html.js'; import './href-sanitizer.js'; +import './json-edit.js'; +import './json-prune.js'; +import './noeval.js'; +import './object-prune.js'; +import './prevent-fetch.js'; +import './prevent-innerHTML.js'; +import './prevent-settimeout.js'; import './replace-argument.js'; import './spoof-css.js'; -import './prevent-settimeout.js'; +import { + generateContentFn, + getExceptionTokenFn, + getRandomTokenFn, + matchObjectPropertiesFn, + parsePropertiesToMatchFn, +} from './utils.js'; import { runAt, runAtHtmlElementFn } from './run-at.js'; import { getAllCookiesFn } from './cookie.js'; import { getAllLocalStorageFn } from './localstorage.js'; +import { matchesStackTraceFn } from './stack-trace.js'; import { proxyApplyFn } from './proxy-apply.js'; import { registeredScriptlets } from './base.js'; import { safeSelf } from './safe-self.js'; @@ -51,41 +66,6 @@ *******************************************************************************/ builtinScriptlets.push({ - name: 'get-random-token.fn', - fn: getRandomToken, - dependencies: [ - 'safe-self.fn', - ], -}); -function getRandomToken() { - const safe = safeSelf(); - return safe.String_fromCharCode(Date.now() % 26 + 97) + - safe.Math_floor(safe.Math_random() * 982451653 + 982451653).toString(36); -} -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'get-exception-token.fn', - fn: getExceptionToken, - dependencies: [ - 'get-random-token.fn', - ], -}); -function getExceptionToken() { - const token = getRandomToken(); - const oe = self.onerror; - self.onerror = function(msg, ...args) { - if ( typeof msg === 'string' && msg.includes(token) ) { return true; } - if ( oe instanceof Function ) { - return oe.call(this, msg, ...args); - } - }.bind(); - return token; -} - -/******************************************************************************/ - -builtinScriptlets.push({ name: 'should-debug.fn', fn: shouldDebug, }); @@ -96,82 +76,9 @@ /******************************************************************************/ -// Reference: -// https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-scriptlets.md#prevent-xhr -// -// Added `trusted` argument to allow for returning arbitrary text. Can only -// be used through scriptlets requiring trusted source. - -builtinScriptlets.push({ - name: 'generate-content.fn', - fn: generateContentFn, - dependencies: [ - 'safe-self.fn', - ], -}); -function generateContentFn(trusted, directive) { - const safe = safeSelf(); - const randomize = len => { - const chunks = []; - let textSize = 0; - do { - const s = safe.Math_random().toString(36).slice(2); - chunks.push(s); - textSize += s.length; - } - while ( textSize < len ); - return chunks.join(' ').slice(0, len); - }; - if ( directive === 'true' ) { - return randomize(10); - } - if ( directive === 'emptyObj' ) { - return '{}'; - } - if ( directive === 'emptyArr' ) { - return '[]'; - } - if ( directive === 'emptyStr' ) { - return ''; - } - if ( directive.startsWith('length:') ) { - const match = /^length:(\d+)(?:-(\d+))?$/.exec(directive); - if ( match === null ) { return ''; } - const min = parseInt(match[1], 10); - const extent = safe.Math_max(parseInt(match[2], 10) || 0, min) - min; - const len = safe.Math_min(min + extent * safe.Math_random(), 500000); - return randomize(len | 0); - } - if ( directive.startsWith('war:') ) { - if ( scriptletGlobals.warOrigin === undefined ) { return ''; } - return new Promise(resolve => { - const warOrigin = scriptletGlobals.warOrigin; - const warName = directive.slice(4); - const fullpath = [ warOrigin, '/', warName ]; - const warSecret = scriptletGlobals.warSecret; - if ( warSecret !== undefined ) { - fullpath.push('?secret=', warSecret); - } - const warXHR = new safe.XMLHttpRequest(); - warXHR.responseType = 'text'; - warXHR.onloadend = ev => { - resolve(ev.target.responseText || ''); - }; - warXHR.open('GET', fullpath.join('')); - warXHR.send(); - }).catch(( ) => ''); - } - if ( trusted ) { - return directive; - } - return ''; -} - -/******************************************************************************/ - builtinScriptlets.push({ - name: 'abort-current-script-core.fn', - fn: abortCurrentScriptCore, + name: 'abort-current-script.fn', + fn: abortCurrentScriptFn, dependencies: [ 'get-exception-token.fn', 'safe-self.fn', @@ -180,7 +87,7 @@ }); // Issues to mind before changing anything: // https://github.com/uBlockOrigin/uBlock-issues/issues/2154 -function abortCurrentScriptCore( +function abortCurrentScriptFn( target = '', needle = '', context = '' @@ -213,10 +120,11 @@ desc = undefined; } const debug = shouldDebug(extraArgs); - const exceptionToken = getExceptionToken(); + const exceptionToken = getExceptionTokenFn(); const scriptTexts = new WeakMap(); + const textContentGetter = Object.getOwnPropertyDescriptor(Node.prototype, 'textContent').get; const getScriptText = elem => { - let text = elem.textContent; + let text = textContentGetter.call(elem); if ( text.trim() !== '' ) { return text; } if ( scriptTexts.has(elem) ) { return scriptTexts.get(elem); } const [ , mime, content ] = @@ -231,7 +139,7 @@ text = self.decodeURIComponent(content); break; } - } catch(ex) { + } catch { } scriptTexts.set(elem, text); return text; @@ -328,7 +236,7 @@ if ( tt instanceof Object ) { if ( typeof tt.getPropertyType === 'function' ) { if ( tt.getPropertyType('script', 'textContent') === 'TrustedScript' ) { - return tt.createPolicy(getRandomToken(), out); + return tt.createPolicy(getRandomTokenFn(), out); } } } @@ -402,348 +310,6 @@ /******************************************************************************/ builtinScriptlets.push({ - name: 'object-prune.fn', - fn: objectPruneFn, - dependencies: [ - 'matches-stack-trace.fn', - 'object-find-owner.fn', - 'safe-self.fn', - ], -}); -// When no "prune paths" argument is provided, the scriptlet is -// used for logging purpose and the "needle paths" argument is -// used to filter logging output. -// -// https://github.com/uBlockOrigin/uBlock-issues/issues/1545 -// - Add support for "remove everything if needle matches" case -function objectPruneFn( - obj, - rawPrunePaths, - rawNeedlePaths, - stackNeedleDetails = { matchAll: true }, - extraArgs = {} -) { - if ( typeof rawPrunePaths !== 'string' ) { return; } - const safe = safeSelf(); - const prunePaths = rawPrunePaths !== '' - ? safe.String_split.call(rawPrunePaths, / +/) - : []; - const needlePaths = prunePaths.length !== 0 && rawNeedlePaths !== '' - ? safe.String_split.call(rawNeedlePaths, / +/) - : []; - if ( stackNeedleDetails.matchAll !== true ) { - if ( matchesStackTraceFn(stackNeedleDetails, extraArgs.logstack) === false ) { - return; - } - } - if ( objectPruneFn.mustProcess === undefined ) { - objectPruneFn.mustProcess = (root, needlePaths) => { - for ( const needlePath of needlePaths ) { - if ( objectFindOwnerFn(root, needlePath) === false ) { - return false; - } - } - return true; - }; - } - if ( prunePaths.length === 0 ) { return; } - let outcome = 'nomatch'; - if ( objectPruneFn.mustProcess(obj, needlePaths) ) { - for ( const path of prunePaths ) { - if ( objectFindOwnerFn(obj, path, true) ) { - outcome = 'match'; - } - } - } - if ( outcome === 'match' ) { return obj; } -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'object-find-owner.fn', - fn: objectFindOwnerFn, -}); -function objectFindOwnerFn( - root, - path, - prune = false -) { - let owner = root; - let chain = path; - for (;;) { - if ( typeof owner !== 'object' || owner === null ) { return false; } - const pos = chain.indexOf('.'); - if ( pos === -1 ) { - if ( prune === false ) { - return owner.hasOwnProperty(chain); - } - let modified = false; - if ( chain === '*' ) { - for ( const key in owner ) { - if ( owner.hasOwnProperty(key) === false ) { continue; } - delete owner[key]; - modified = true; - } - } else if ( owner.hasOwnProperty(chain) ) { - delete owner[chain]; - modified = true; - } - return modified; - } - const prop = chain.slice(0, pos); - const next = chain.slice(pos + 1); - let found = false; - if ( prop === '[-]' && Array.isArray(owner) ) { - let i = owner.length; - while ( i-- ) { - if ( objectFindOwnerFn(owner[i], next) === false ) { continue; } - owner.splice(i, 1); - found = true; - } - return found; - } - if ( prop === '{-}' && owner instanceof Object ) { - for ( const key of Object.keys(owner) ) { - if ( objectFindOwnerFn(owner[key], next) === false ) { continue; } - delete owner[key]; - found = true; - } - return found; - } - if ( - prop === '[]' && Array.isArray(owner) || - prop === '{}' && owner instanceof Object || - prop === '*' && owner instanceof Object - ) { - for ( const key of Object.keys(owner) ) { - if (objectFindOwnerFn(owner[key], next, prune) === false ) { continue; } - found = true; - } - return found; - } - if ( owner.hasOwnProperty(prop) === false ) { return false; } - owner = owner[prop]; - chain = chain.slice(pos + 1); - } -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'matches-stack-trace.fn', - fn: matchesStackTraceFn, - dependencies: [ - 'get-exception-token.fn', - 'safe-self.fn', - ], -}); -function matchesStackTraceFn( - needleDetails, - logLevel = '' -) { - const safe = safeSelf(); - const exceptionToken = getExceptionToken(); - const error = new safe.Error(exceptionToken); - const docURL = new URL(self.location.href); - docURL.hash = ''; - // Normalize stack trace - const reLine = /(.*?@)?(\S+)(:\d+):\d+\)?$/; - const lines = []; - for ( let line of safe.String_split.call(error.stack, /[\n\r]+/) ) { - if ( line.includes(exceptionToken) ) { continue; } - line = line.trim(); - const match = safe.RegExp_exec.call(reLine, line); - if ( match === null ) { continue; } - let url = match[2]; - if ( url.startsWith('(') ) { url = url.slice(1); } - if ( url === docURL.href ) { - url = 'inlineScript'; - } else if ( url.startsWith('') ) { - url = 'injectedScript'; - } - let fn = match[1] !== undefined - ? match[1].slice(0, -1) - : line.slice(0, match.index).trim(); - if ( fn.startsWith('at') ) { fn = fn.slice(2).trim(); } - let rowcol = match[3]; - lines.push(' ' + `${fn} ${url}${rowcol}:1`.trim()); - } - lines[0] = `stackDepth:${lines.length-1}`; - const stack = lines.join('\t'); - const r = needleDetails.matchAll !== true && - safe.testPattern(needleDetails, stack); - if ( - logLevel === 'all' || - logLevel === 'match' && r || - logLevel === 'nomatch' && !r - ) { - safe.uboLog(stack.replace(/\t/g, '\n')); - } - return r; -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'parse-properties-to-match.fn', - fn: parsePropertiesToMatch, - dependencies: [ - 'safe-self.fn', - ], -}); -function parsePropertiesToMatch(propsToMatch, implicit = '') { - const safe = safeSelf(); - const needles = new Map(); - if ( propsToMatch === undefined || propsToMatch === '' ) { return needles; } - const options = { canNegate: true }; - for ( const needle of safe.String_split.call(propsToMatch, /\s+/) ) { - let [ prop, pattern ] = safe.String_split.call(needle, ':'); - if ( prop === '' ) { continue; } - if ( pattern !== undefined && /[^$\w -]/.test(prop) ) { - prop = `${prop}:${pattern}`; - pattern = undefined; - } - if ( pattern !== undefined ) { - needles.set(prop, safe.initPattern(pattern, options)); - } else if ( implicit !== '' ) { - needles.set(implicit, safe.initPattern(prop, options)); - } - } - return needles; -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'match-object-properties.fn', - fn: matchObjectProperties, - dependencies: [ - 'safe-self.fn', - ], -}); -function matchObjectProperties(propNeedles, ...objs) { - if ( matchObjectProperties.extractProperties === undefined ) { - matchObjectProperties.extractProperties = (src, des, props) => { - for ( const p of props ) { - const v = src[p]; - if ( v === undefined ) { continue; } - des[p] = src[p]; - } - }; - } - const safe = safeSelf(); - const haystack = {}; - const props = safe.Array_from(propNeedles.keys()); - for ( const obj of objs ) { - if ( obj instanceof Object === false ) { continue; } - matchObjectProperties.extractProperties(obj, haystack, props); - } - for ( const [ prop, details ] of propNeedles ) { - let value = haystack[prop]; - if ( value === undefined ) { continue; } - if ( typeof value !== 'string' ) { - try { value = safe.JSON_stringify(value); } - catch(ex) { } - if ( typeof value !== 'string' ) { continue; } - } - if ( safe.testPattern(details, value) ) { continue; } - return false; - } - return true; -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'json-prune-fetch-response.fn', - fn: jsonPruneFetchResponseFn, - dependencies: [ - 'match-object-properties.fn', - 'object-prune.fn', - 'parse-properties-to-match.fn', - 'safe-self.fn', - ], -}); -function jsonPruneFetchResponseFn( - rawPrunePaths = '', - rawNeedlePaths = '' -) { - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('json-prune-fetch-response', rawPrunePaths, rawNeedlePaths); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); - const propNeedles = parsePropertiesToMatch(extraArgs.propsToMatch, 'url'); - const stackNeedle = safe.initPattern(extraArgs.stackToMatch || '', { canNegate: true }); - const logall = rawPrunePaths === ''; - const applyHandler = function(target, thisArg, args) { - const fetchPromise = Reflect.apply(target, thisArg, args); - let outcome = logall ? 'nomatch' : 'match'; - if ( propNeedles.size !== 0 ) { - const objs = [ args[0] instanceof Object ? args[0] : { url: args[0] } ]; - if ( objs[0] instanceof Request ) { - try { - objs[0] = safe.Request_clone.call(objs[0]); - } catch(ex) { - safe.uboErr(logPrefix, 'Error:', ex); - } - } - if ( args[1] instanceof Object ) { - objs.push(args[1]); - } - if ( matchObjectProperties(propNeedles, ...objs) === false ) { - outcome = 'nomatch'; - } - } - if ( logall === false && outcome === 'nomatch' ) { return fetchPromise; } - if ( safe.logLevel > 1 && outcome !== 'nomatch' && propNeedles.size !== 0 ) { - safe.uboLog(logPrefix, `Matched optional "propsToMatch"\n${extraArgs.propsToMatch}`); - } - return fetchPromise.then(responseBefore => { - const response = responseBefore.clone(); - return response.json().then(objBefore => { - if ( typeof objBefore !== 'object' ) { return responseBefore; } - if ( logall ) { - safe.uboLog(logPrefix, safe.JSON_stringify(objBefore, null, 2)); - return responseBefore; - } - const objAfter = objectPruneFn( - objBefore, - rawPrunePaths, - rawNeedlePaths, - stackNeedle, - extraArgs - ); - if ( typeof objAfter !== 'object' ) { return responseBefore; } - safe.uboLog(logPrefix, 'Pruned'); - const responseAfter = Response.json(objAfter, { - status: responseBefore.status, - statusText: responseBefore.statusText, - headers: responseBefore.headers, - }); - Object.defineProperties(responseAfter, { - ok: { value: responseBefore.ok }, - redirected: { value: responseBefore.redirected }, - type: { value: responseBefore.type }, - url: { value: responseBefore.url }, - }); - return responseAfter; - }).catch(reason => { - safe.uboErr(logPrefix, 'Error:', reason); - return responseBefore; - }); - }).catch(reason => { - safe.uboErr(logPrefix, 'Error:', reason); - return fetchPromise; - }); - }; - self.fetch = new Proxy(self.fetch, { - apply: applyHandler - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ name: 'replace-fetch-response.fn', fn: replaceFetchResponseFn, dependencies: [ @@ -763,14 +329,13 @@ const logPrefix = safe.makeLogPrefix('replace-fetch-response', pattern, replacement, propsToMatch); if ( pattern === '*' ) { pattern = '.*'; } const rePattern = safe.patternToRegex(pattern); - const propNeedles = parsePropertiesToMatch(propsToMatch, 'url'); + const propNeedles = parsePropertiesToMatchFn(propsToMatch, 'url'); const extraArgs = safe.getExtraArgs(Array.from(arguments), 4); const reIncludes = extraArgs.includes ? safe.patternToRegex(extraArgs.includes) : null; self.fetch = new Proxy(self.fetch, { apply: function(target, thisArg, args) { const fetchPromise = Reflect.apply(target, thisArg, args); if ( pattern === '' ) { return fetchPromise; } - let outcome = 'match'; if ( propNeedles.size !== 0 ) { const objs = [ args[0] instanceof Object ? args[0] : { url: args[0] } ]; if ( objs[0] instanceof Request ) { @@ -784,14 +349,12 @@ if ( args[1] instanceof Object ) { objs.push(args[1]); } - if ( matchObjectProperties(propNeedles, ...objs) === false ) { - outcome = 'nomatch'; + const matched = matchObjectPropertiesFn(propNeedles, ...objs); + if ( matched === undefined ) { return fetchPromise; } + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `Matched "propsToMatch":\n\t${matched.join('\n\t')}`); } } - if ( outcome === 'nomatch' ) { return fetchPromise; } - if ( safe.logLevel > 1 ) { - safe.uboLog(logPrefix, `Matched "propsToMatch"\n${propsToMatch}`); - } return fetchPromise.then(responseBefore => { const response = responseBefore.clone(); return response.text().then(textBefore => { @@ -799,8 +362,7 @@ return responseBefore; } const textAfter = textBefore.replace(rePattern, replacement); - const outcome = textAfter !== textBefore ? 'match' : 'nomatch'; - if ( outcome === 'nomatch' ) { return responseBefore; } + if ( textAfter === textBefore ) { return responseBefore; } safe.uboLog(logPrefix, 'Replaced'); const responseAfter = new Response(textAfter, { status: responseBefore.status, @@ -848,12 +410,12 @@ const scriptletName = trusted ? 'trusted-prevent-xhr' : 'prevent-xhr'; const logPrefix = safe.makeLogPrefix(scriptletName, propsToMatch, directive); const xhrInstances = new WeakMap(); - const propNeedles = parsePropertiesToMatch(propsToMatch, 'url'); + const propNeedles = parsePropertiesToMatchFn(propsToMatch, 'url'); const warOrigin = scriptletGlobals.warOrigin; const safeDispatchEvent = (xhr, type) => { try { xhr.dispatchEvent(new Event(type)); - } catch(_) { + } catch { } }; const XHRBefore = XMLHttpRequest.prototype; @@ -868,7 +430,7 @@ safe.uboLog(logPrefix, `Called: ${safe.JSON_stringify(haystack, null, 2)}`); return super.open(method, url, ...args); } - if ( matchObjectProperties(propNeedles, haystack) ) { + if ( matchObjectPropertiesFn(propNeedles, haystack) ) { const xhrDetails = Object.assign(haystack, { xhr: this, defer: args.length === 0 || !!args[0], @@ -1035,7 +597,7 @@ ], fn: abortCurrentScript, dependencies: [ - 'abort-current-script-core.fn', + 'abort-current-script.fn', 'run-at-html-element.fn', ], }); @@ -1043,7 +605,7 @@ // https://github.com/uBlockOrigin/uBlock-issues/issues/2154 function abortCurrentScript(...args) { runAtHtmlElementFn(( ) => { - abortCurrentScriptCore(...args); + abortCurrentScriptFn(...args); }); } @@ -1067,7 +629,7 @@ if ( chain === '' ) { return; } const safe = safeSelf(); const logPrefix = safe.makeLogPrefix('abort-on-property-read', chain); - const exceptionToken = getExceptionToken(); + const exceptionToken = getExceptionTokenFn(); const abort = function() { safe.uboLog(logPrefix, 'Aborted'); throw new ReferenceError(exceptionToken); @@ -1127,7 +689,7 @@ if ( prop === '' ) { return; } const safe = safeSelf(); const logPrefix = safe.makeLogPrefix('abort-on-property-write', prop); - const exceptionToken = getExceptionToken(); + const exceptionToken = getExceptionTokenFn(); let owner = window; for (;;) { const pos = prop.indexOf('.'); @@ -1148,72 +710,6 @@ /******************************************************************************/ builtinScriptlets.push({ - name: 'abort-on-stack-trace.js', - aliases: [ - 'aost.js', - ], - fn: abortOnStackTrace, - dependencies: [ - 'get-exception-token.fn', - 'matches-stack-trace.fn', - 'safe-self.fn', - ], -}); -function abortOnStackTrace( - chain = '', - needle = '' -) { - if ( typeof chain !== 'string' ) { return; } - const safe = safeSelf(); - const needleDetails = safe.initPattern(needle, { canNegate: true }); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); - if ( needle === '' ) { extraArgs.log = 'all'; } - const makeProxy = function(owner, chain) { - const pos = chain.indexOf('.'); - if ( pos === -1 ) { - let v = owner[chain]; - Object.defineProperty(owner, chain, { - get: function() { - if ( matchesStackTraceFn(needleDetails, extraArgs.log) ) { - throw new ReferenceError(getExceptionToken()); - } - return v; - }, - set: function(a) { - if ( matchesStackTraceFn(needleDetails, extraArgs.log) ) { - throw new ReferenceError(getExceptionToken()); - } - v = a; - }, - }); - return; - } - const prop = chain.slice(0, pos); - let v = owner[prop]; - chain = chain.slice(pos + 1); - if ( v ) { - makeProxy(v, chain); - return; - } - const desc = Object.getOwnPropertyDescriptor(owner, prop); - if ( desc && desc.set !== undefined ) { return; } - Object.defineProperty(owner, prop, { - get: function() { return v; }, - set: function(a) { - v = a; - if ( a instanceof Object ) { - makeProxy(a, chain); - } - } - }); - }; - const owner = window; - makeProxy(owner, chain); -} - -/******************************************************************************/ - -builtinScriptlets.push({ name: 'addEventListener-defuser.js', aliases: [ 'aeld.js', @@ -1278,213 +774,33 @@ } return matchesBoth; }; - runAt(( ) => { - proxyApplyFn('EventTarget.prototype.addEventListener', function(context) { - const { callArgs, thisArg } = context; - let t, h; - try { - t = String(callArgs[0]); - if ( typeof callArgs[1] === 'function' ) { - h = String(safe.Function_toString(callArgs[1])); - } else if ( typeof callArgs[1] === 'object' && callArgs[1] !== null ) { - if ( typeof callArgs[1].handleEvent === 'function' ) { - h = String(safe.Function_toString(callArgs[1].handleEvent)); - } - } else { - h = String(callArgs[1]); - } - } catch(ex) { - } - if ( type === '' && pattern === '' ) { - safe.uboLog(logPrefix, `Called: ${t}\n${h}\n${elementDetails(thisArg)}`); - } else if ( shouldPrevent(thisArg, t, h) ) { - return safe.uboLog(logPrefix, `Prevented: ${t}\n${h}\n${elementDetails(thisArg)}`); - } - return context.reflect(); - }); - }, extraArgs.runAt); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'json-prune.js', - fn: jsonPrune, - dependencies: [ - 'object-prune.fn', - 'safe-self.fn', - ], -}); -function jsonPrune( - rawPrunePaths = '', - rawNeedlePaths = '', - stackNeedle = '' -) { - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('json-prune', rawPrunePaths, rawNeedlePaths, stackNeedle); - const stackNeedleDetails = safe.initPattern(stackNeedle, { canNegate: true }); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); - JSON.parse = new Proxy(JSON.parse, { - apply: function(target, thisArg, args) { - const objBefore = Reflect.apply(target, thisArg, args); - if ( rawPrunePaths === '' ) { - safe.uboLog(logPrefix, safe.JSON_stringify(objBefore, null, 2)); - } - const objAfter = objectPruneFn( - objBefore, - rawPrunePaths, - rawNeedlePaths, - stackNeedleDetails, - extraArgs - ); - if ( objAfter === undefined ) { return objBefore; } - safe.uboLog(logPrefix, 'Pruned'); - if ( safe.logLevel > 1 ) { - safe.uboLog(logPrefix, `After pruning:\n${safe.JSON_stringify(objAfter, null, 2)}`); - } - return objAfter; - }, - }); -} - -/******************************************************************************* - * - * json-prune-fetch-response.js - * - * Prune JSON response of fetch requests. - * - **/ - -builtinScriptlets.push({ - name: 'json-prune-fetch-response.js', - fn: jsonPruneFetchResponse, - dependencies: [ - 'json-prune-fetch-response.fn', - ], -}); -function jsonPruneFetchResponse(...args) { - jsonPruneFetchResponseFn(...args); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'json-prune-xhr-response.js', - fn: jsonPruneXhrResponse, - dependencies: [ - 'match-object-properties.fn', - 'object-prune.fn', - 'parse-properties-to-match.fn', - 'safe-self.fn', - ], -}); -function jsonPruneXhrResponse( - rawPrunePaths = '', - rawNeedlePaths = '' -) { - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('json-prune-xhr-response', rawPrunePaths, rawNeedlePaths); - const xhrInstances = new WeakMap(); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); - const propNeedles = parsePropertiesToMatch(extraArgs.propsToMatch, 'url'); - const stackNeedle = safe.initPattern(extraArgs.stackToMatch || '', { canNegate: true }); - self.XMLHttpRequest = class extends self.XMLHttpRequest { - open(method, url, ...args) { - const xhrDetails = { method, url }; - let outcome = 'match'; - if ( propNeedles.size !== 0 ) { - if ( matchObjectProperties(propNeedles, xhrDetails) === false ) { - outcome = 'nomatch'; - } - } - if ( outcome === 'match' ) { - if ( safe.logLevel > 1 ) { - safe.uboLog(logPrefix, `Matched optional "propsToMatch", "${extraArgs.propsToMatch}"`); - } - xhrInstances.set(this, xhrDetails); - } - return super.open(method, url, ...args); - } - get response() { - const innerResponse = super.response; - const xhrDetails = xhrInstances.get(this); - if ( xhrDetails === undefined ) { - return innerResponse; - } - const responseLength = typeof innerResponse === 'string' - ? innerResponse.length - : undefined; - if ( xhrDetails.lastResponseLength !== responseLength ) { - xhrDetails.response = undefined; - xhrDetails.lastResponseLength = responseLength; - } - if ( xhrDetails.response !== undefined ) { - return xhrDetails.response; - } - let objBefore; - if ( typeof innerResponse === 'object' ) { - objBefore = innerResponse; - } else if ( typeof innerResponse === 'string' ) { - try { - objBefore = safe.JSON_parse(innerResponse); - } catch(ex) { + const proxyFn = function(context) { + const { callArgs, thisArg } = context; + let t, h; + try { + t = String(callArgs[0]); + if ( typeof callArgs[1] === 'function' ) { + h = String(safe.Function_toString(callArgs[1])); + } else if ( typeof callArgs[1] === 'object' && callArgs[1] !== null ) { + if ( typeof callArgs[1].handleEvent === 'function' ) { + h = String(safe.Function_toString(callArgs[1].handleEvent)); } - } - if ( typeof objBefore !== 'object' ) { - return (xhrDetails.response = innerResponse); - } - const objAfter = objectPruneFn( - objBefore, - rawPrunePaths, - rawNeedlePaths, - stackNeedle, - extraArgs - ); - let outerResponse; - if ( typeof objAfter === 'object' ) { - outerResponse = typeof innerResponse === 'string' - ? safe.JSON_stringify(objAfter) - : objAfter; - safe.uboLog(logPrefix, 'Pruned'); } else { - outerResponse = innerResponse; + h = String(callArgs[1]); } - return (xhrDetails.response = outerResponse); + } catch { } - get responseText() { - const response = this.response; - return typeof response !== 'string' - ? super.responseText - : response; + if ( type === '' && pattern === '' ) { + safe.uboLog(logPrefix, `Called: ${t}\n${h}\n${elementDetails(thisArg)}`); + } else if ( shouldPrevent(thisArg, t, h) ) { + return safe.uboLog(logPrefix, `Prevented: ${t}\n${h}\n${elementDetails(thisArg)}`); } + return context.reflect(); }; -} - -/******************************************************************************/ - -// There is still code out there which uses `eval` in lieu of `JSON.parse`. - -builtinScriptlets.push({ - name: 'evaldata-prune.js', - fn: evaldataPrune, - dependencies: [ - 'object-prune.fn', - ], -}); -function evaldataPrune( - rawPrunePaths = '', - rawNeedlePaths = '' -) { - self.eval = new Proxy(self.eval, { - apply(target, thisArg, args) { - const before = Reflect.apply(target, thisArg, args); - if ( typeof before === 'object' ) { - const after = objectPruneFn(before, rawPrunePaths, rawNeedlePaths); - return after || before; - } - return before; - } - }); + runAt(( ) => { + proxyApplyFn('EventTarget.prototype.addEventListener', proxyFn); + proxyApplyFn('document.addEventListener', proxyFn); + }, extraArgs.runAt); } /******************************************************************************/ @@ -1597,153 +913,6 @@ /******************************************************************************/ builtinScriptlets.push({ - name: 'noeval-if.js', - aliases: [ - 'prevent-eval-if.js', - ], - fn: noEvalIf, - dependencies: [ - 'safe-self.fn', - ], -}); -function noEvalIf( - needle = '' -) { - if ( typeof needle !== 'string' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('noeval-if', needle); - const reNeedle = safe.patternToRegex(needle); - window.eval = new Proxy(window.eval, { // jshint ignore: line - apply: function(target, thisArg, args) { - const a = String(args[0]); - if ( needle !== '' && reNeedle.test(a) ) { - safe.uboLog(logPrefix, 'Prevented:\n', a); - return; - } - if ( needle === '' || safe.logLevel > 1 ) { - safe.uboLog(logPrefix, 'Not prevented:\n', a); - } - return Reflect.apply(target, thisArg, args); - } - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'prevent-fetch.js', - aliases: [ - 'no-fetch-if.js', - ], - fn: noFetchIf, - dependencies: [ - 'generate-content.fn', - 'proxy-apply.fn', - 'safe-self.fn', - ], -}); -function noFetchIf( - propsToMatch = '', - responseBody = '', - responseType = '' -) { - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('prevent-fetch', propsToMatch, responseBody, responseType); - const needles = []; - for ( const condition of safe.String_split.call(propsToMatch, /\s+/) ) { - if ( condition === '' ) { continue; } - const pos = condition.indexOf(':'); - let key, value; - if ( pos !== -1 ) { - key = condition.slice(0, pos); - value = condition.slice(pos + 1); - } else { - key = 'url'; - value = condition; - } - needles.push({ key, pattern: safe.initPattern(value, { canNegate: true }) }); - } - const validResponseProps = { - ok: [ false, true ], - statusText: [ '', 'Not Found' ], - type: [ 'basic', 'cors', 'default', 'error', 'opaque' ], - }; - const responseProps = { - statusText: { value: 'OK' }, - }; - if ( /^\{.*\}$/.test(responseType) ) { - try { - Object.entries(JSON.parse(responseType)).forEach(([ p, v ]) => { - if ( validResponseProps[p] === undefined ) { return; } - if ( validResponseProps[p].includes(v) === false ) { return; } - responseProps[p] = { value: v }; - }); - } - catch(ex) {} - } else if ( responseType !== '' ) { - if ( validResponseProps.type.includes(responseType) ) { - responseProps.type = { value: responseType }; - } - } - proxyApplyFn('fetch', function fetch(context) { - const { callArgs } = context; - const details = callArgs[0] instanceof self.Request - ? callArgs[0] - : Object.assign({ url: callArgs[0] }, callArgs[1]); - let proceed = true; - try { - const props = new Map(); - for ( const prop in details ) { - let v = details[prop]; - if ( typeof v !== 'string' ) { - try { v = safe.JSON_stringify(v); } - catch(ex) { } - } - if ( typeof v !== 'string' ) { continue; } - props.set(prop, v); - } - if ( safe.logLevel > 1 || propsToMatch === '' && responseBody === '' ) { - const out = Array.from(props).map(a => `${a[0]}:${a[1]}`); - safe.uboLog(logPrefix, `Called: ${out.join('\n')}`); - } - if ( propsToMatch === '' && responseBody === '' ) { - return context.reflect(); - } - proceed = needles.length === 0; - for ( const { key, pattern } of needles ) { - if ( - pattern.expect && props.has(key) === false || - safe.testPattern(pattern, props.get(key)) === false - ) { - proceed = true; - break; - } - } - } catch(ex) { - } - if ( proceed ) { - return context.reflect(); - } - return Promise.resolve(generateContentFn(false, responseBody)).then(text => { - safe.uboLog(logPrefix, `Prevented with response "${text}"`); - const response = new Response(text, { - headers: { - 'Content-Length': text.length, - } - }); - const props = Object.assign( - { url: { value: details.url } }, - responseProps - ); - safe.Object_defineProperties(response, props); - return response; - }); - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ name: 'prevent-refresh.js', aliases: [ 'refresh-defuser.js', @@ -1821,7 +990,7 @@ node.classList.remove(...tokens); safe.uboLog(logPrefix, 'Removed class(es)'); } - } catch(ex) { + } catch { } if ( mustStay ) { return; } if ( document.readyState !== 'complete' ) { return; } @@ -2134,8 +1303,8 @@ // Experimental: Generic nuisance overlay buster. // if this works well and proves to be useful, this may end up // as a stock tool in uBO's popup panel. -function overlayBuster() { - if ( window !== window.top ) { return; } +function overlayBuster(allFrames) { + if ( allFrames === '' && window !== window.top ) { return; } var tstart; var ttl = 30000; var delay = 0; @@ -2253,8 +1422,8 @@ }); // https://github.com/uBlockOrigin/uAssets/issues/913 function disableNewtabLinks() { - document.addEventListener('click', function(ev) { - var target = ev.target; + document.addEventListener('click', ev => { + let target = ev.target; while ( target !== null ) { if ( target.localName === 'a' && target.hasAttribute('target') ) { ev.stopPropagation(); @@ -2263,7 +1432,7 @@ } target = target.parentNode; } - }); + }, { capture: true }); } /******************************************************************************/ @@ -2340,7 +1509,7 @@ pruneFromDoc(xmlDoc); const serializer = new XMLSerializer(); text = serializer.serializeToString(xmlDoc); - } catch(ex) { + } catch { } return text; }; @@ -2634,7 +1803,7 @@ let r; try { r = Reflect.apply(...args); - } catch(ex) { + } catch { } return r; }, @@ -2859,7 +2028,7 @@ const xhrInstances = new WeakMap(); if ( pattern === '*' ) { pattern = '.*'; } const rePattern = safe.patternToRegex(pattern); - const propNeedles = parsePropertiesToMatch(propsToMatch, 'url'); + const propNeedles = parsePropertiesToMatchFn(propsToMatch, 'url'); const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); const reIncludes = extraArgs.includes ? safe.patternToRegex(extraArgs.includes) : null; self.XMLHttpRequest = class extends self.XMLHttpRequest { @@ -2868,7 +2037,7 @@ const xhrDetails = { method, url }; let outcome = 'match'; if ( propNeedles.size !== 0 ) { - if ( matchObjectProperties(propNeedles, xhrDetails) === false ) { + if ( matchObjectPropertiesFn(propNeedles, xhrDetails) === undefined ) { outcome = 'nomatch'; } } @@ -3017,209 +2186,109 @@ return shadowRoot && querySelectorEx(inside, shadowRoot); }; - const selectorList = safe.String_split.call(selectors, /\s*,\s*/) - .filter(s => { - try { - void querySelectorEx(s); - } catch(_) { - return false; - } - return true; - }); - if ( selectorList.length === 0 ) { return; } - + const steps = safe.String_split.call(selectors, /\s*,\s*/).map(a => { + if ( /^\d+$/.test(a) ) { return parseInt(a, 10); } + return a; + }); + if ( steps.length === 0 ) { return; } const clickDelay = parseInt(delay, 10) || 1; - const t0 = Date.now(); - const tbye = t0 + 10000; - let tnext = selectorList.length !== 1 ? t0 : t0 + clickDelay; + for ( let i = steps.length-1; i > 0; i-- ) { + if ( typeof steps[i] !== 'string' ) { continue; } + if ( typeof steps[i-1] !== 'string' ) { continue; } + steps.splice(i, 0, clickDelay); + } + if ( steps.length === 1 && delay !== '' ) { + steps.unshift(clickDelay); + } + if ( typeof steps.at(-1) !== 'number' ) { + steps.push(10000); + } - const terminate = ( ) => { - selectorList.length = 0; - next.stop(); - observe.stop(); - }; - - const next = notFound => { - if ( selectorList.length === 0 ) { - safe.uboLog(logPrefix, 'Completed'); - return terminate(); - } - const tnow = Date.now(); - if ( tnow >= tbye ) { - safe.uboLog(logPrefix, 'Timed out'); - return terminate(); - } - if ( notFound ) { observe(); } - const delay = Math.max(notFound ? tbye - tnow : tnext - tnow, 1); - next.timer = setTimeout(( ) => { - next.timer = undefined; - process(); - }, delay); - safe.uboLog(logPrefix, `Waiting for ${selectorList[0]}...`); - }; - next.stop = ( ) => { - if ( next.timer === undefined ) { return; } - clearTimeout(next.timer); - next.timer = undefined; - }; - - const observe = ( ) => { - if ( observe.observer !== undefined ) { return; } - observe.observer = new MutationObserver(( ) => { - if ( observe.timer !== undefined ) { return; } - observe.timer = setTimeout(( ) => { - observe.timer = undefined; - process(); - }, 20); - }); - observe.observer.observe(document, { - attributes: true, - childList: true, - subtree: true, + const waitForTime = ms => { + return new Promise(resolve => { + safe.uboLog(logPrefix, `Waiting for ${ms} ms`); + waitForTime.timer = setTimeout(( ) => { + waitForTime.timer = undefined; + resolve(); + }, ms); }); }; - observe.stop = ( ) => { - if ( observe.timer !== undefined ) { - clearTimeout(observe.timer); - observe.timer = undefined; - } - if ( observe.observer ) { - observe.observer.disconnect(); - observe.observer = undefined; - } + waitForTime.cancel = ( ) => { + const { timer } = waitForTime; + if ( timer === undefined ) { return; } + clearTimeout(timer); + waitForTime.timer = undefined; }; - const process = ( ) => { - next.stop(); - if ( Date.now() < tnext ) { return next(); } - const selector = selectorList.shift(); - if ( selector === undefined ) { return terminate(); } - const elem = querySelectorEx(selector); - if ( elem === null ) { - selectorList.unshift(selector); - return next(true); - } - safe.uboLog(logPrefix, `Clicked ${selector}`); - elem.click(); - tnext += clickDelay; - next(); + const waitForElement = selector => { + return new Promise(resolve => { + const elem = querySelectorEx(selector); + if ( elem !== null ) { + elem.click(); + resolve(); + return; + } + safe.uboLog(logPrefix, `Waiting for ${selector}`); + const observer = new MutationObserver(( ) => { + const elem = querySelectorEx(selector); + if ( elem === null ) { return; } + waitForElement.cancel(); + elem.click(); + resolve(); + }); + observer.observe(document, { + attributes: true, + childList: true, + subtree: true, + }); + waitForElement.observer = observer; + }); + }; + waitForElement.cancel = ( ) => { + const { observer } = waitForElement; + if ( observer === undefined ) { return; } + waitForElement.observer = undefined; + observer.disconnect(); }; - runAtHtmlElementFn(process); -} - -/******************************************************************************/ + const waitForTimeout = ms => { + waitForTimeout.cancel(); + waitForTimeout.timer = setTimeout(( ) => { + waitForTimeout.timer = undefined; + terminate(); + safe.uboLog(logPrefix, `Timed out after ${ms} ms`); + }, ms); + }; + waitForTimeout.cancel = ( ) => { + if ( waitForTimeout.timer === undefined ) { return; } + clearTimeout(waitForTimeout.timer); + waitForTimeout.timer = undefined; + }; -builtinScriptlets.push({ - name: 'trusted-prune-inbound-object.js', - requiresTrust: true, - fn: trustedPruneInboundObject, - dependencies: [ - 'object-find-owner.fn', - 'object-prune.fn', - 'safe-self.fn', - ], -}); -function trustedPruneInboundObject( - entryPoint = '', - argPos = '', - rawPrunePaths = '', - rawNeedlePaths = '' -) { - if ( entryPoint === '' ) { return; } - let context = globalThis; - let prop = entryPoint; - for (;;) { - const pos = prop.indexOf('.'); - if ( pos === -1 ) { break; } - context = context[prop.slice(0, pos)]; - if ( context instanceof Object === false ) { return; } - prop = prop.slice(pos+1); - } - if ( typeof context[prop] !== 'function' ) { return; } - const argIndex = parseInt(argPos); - if ( isNaN(argIndex) ) { return; } - if ( argIndex < 1 ) { return; } - const safe = safeSelf(); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 4); - const needlePaths = []; - if ( rawPrunePaths !== '' ) { - needlePaths.push(...safe.String_split.call(rawPrunePaths, / +/)); - } - if ( rawNeedlePaths !== '' ) { - needlePaths.push(...safe.String_split.call(rawNeedlePaths, / +/)); - } - const stackNeedle = safe.initPattern(extraArgs.stackToMatch || '', { canNegate: true }); - const mustProcess = root => { - for ( const needlePath of needlePaths ) { - if ( objectFindOwnerFn(root, needlePath) === false ) { - return false; - } + const terminate = ( ) => { + waitForTime.cancel(); + waitForElement.cancel(); + waitForTimeout.cancel(); + }; + + const process = async ( ) => { + waitForTimeout(steps.pop()); + while ( steps.length !== 0 ) { + const step = steps.shift(); + if ( step === undefined ) { break; } + if ( typeof step === 'number' ) { + await waitForTime(step); + if ( step === 1 ) { continue; } + continue; + } + if ( step.startsWith('!') ) { continue; } + await waitForElement(step); + safe.uboLog(logPrefix, `Clicked ${step}`); } - return true; + terminate(); }; - context[prop] = new Proxy(context[prop], { - apply: function(target, thisArg, args) { - const targetArg = argIndex <= args.length - ? args[argIndex-1] - : undefined; - if ( targetArg instanceof Object && mustProcess(targetArg) ) { - let objBefore = targetArg; - if ( extraArgs.dontOverwrite ) { - try { - objBefore = safe.JSON_parse(safe.JSON_stringify(targetArg)); - } catch(_) { - objBefore = undefined; - } - } - if ( objBefore !== undefined ) { - const objAfter = objectPruneFn( - objBefore, - rawPrunePaths, - rawNeedlePaths, - stackNeedle, - extraArgs - ); - args[argIndex-1] = objAfter || objBefore; - } - } - return Reflect.apply(target, thisArg, args); - }, - }); -} - -/******************************************************************************/ -builtinScriptlets.push({ - name: 'trusted-prune-outbound-object.js', - requiresTrust: true, - fn: trustedPruneOutboundObject, - dependencies: [ - 'object-prune.fn', - 'proxy-apply.fn', - 'safe-self.fn', - ], -}); -function trustedPruneOutboundObject( - propChain = '', - rawPrunePaths = '', - rawNeedlePaths = '' -) { - if ( propChain === '' ) { return; } - const safe = safeSelf(); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); - proxyApplyFn(propChain, function(context) { - const objBefore = context.reflect(); - if ( objBefore instanceof Object === false ) { return objBefore; } - const objAfter = objectPruneFn( - objBefore, - rawPrunePaths, - rawNeedlePaths, - { matchAll: true }, - extraArgs - ); - return objAfter || objBefore; - }); + runAtHtmlElementFn(process); } /******************************************************************************/ @@ -3253,7 +2322,7 @@ let textBefore = encodedTextBefore; if ( extraArgs.encoding === 'base64' ) { try { textBefore = self.atob(encodedTextBefore); } - catch(ex) { return encodedTextBefore; } + catch { return encodedTextBefore; } } if ( rawPattern === '' ) { safe.uboLog(logPrefix, 'Decoded outbound text:\n', textBefore); @@ -3449,12 +2518,21 @@ } } if ( targetProp !== '' ) { - elem.contentWindow[targetProp] = self[targetProp]; + let me = self, it = elem.contentWindow; + let chain = targetProp; + for (;;) { + const pos = chain.indexOf('.'); + if ( pos === -1 ) { break; } + const prop = chain.slice(0, pos); + me = me[prop]; it = it[prop]; + chain = chain.slice(pos+1); + } + it[chain] = me[chain]; } else { Object.defineProperty(elem, 'contentWindow', { value: self }); } safe.uboLog(logPrefix, 'Bypass prevented'); - } catch(_) { + } catch { } } return r; @@ -3503,13 +2581,14 @@ if ( methodPath === '' ) { return; } const safe = safeSelf(); const logPrefix = safe.makeLogPrefix('trusted-override-element-method', methodPath, selector, disposition); + const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); proxyApplyFn(methodPath, function(context) { let override = selector === ''; if ( override === false ) { const { thisArg } = context; try { override = thisArg.closest(selector) === thisArg; - } catch(_) { + } catch { } } if ( override === false ) { @@ -3523,7 +2602,7 @@ if ( disposition === 'throw' ) { throw new ReferenceError(); } - return validateConstantFn(false, disposition); + return validateConstantFn(true, disposition, extraArgs); }); } diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/set-constant.js ublock-origin-1.67.0+dfsg/src/js/resources/set-constant.js --- ublock-origin-1.62.0+dfsg/src/js/resources/set-constant.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/set-constant.js 2025-10-25 19:32:51.000000000 +0000 @@ -57,9 +57,9 @@ if ( Math.abs(raw) > 0x7FFF ) { return; } } else if ( trusted ) { if ( raw.startsWith('json:') ) { - try { value = safe.JSON_parse(raw.slice(5)); } catch(ex) { return; } + try { value = safe.JSON_parse(raw.slice(5)); } catch { return; } } else if ( raw.startsWith('{') && raw.endsWith('}') ) { - try { value = safe.JSON_parse(raw).value; } catch(ex) { return; } + try { value = safe.JSON_parse(raw).value; } catch { return; } } } else { return; diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/shared.js ublock-origin-1.67.0+dfsg/src/js/resources/shared.js --- ublock-origin-1.62.0+dfsg/src/js/resources/shared.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/shared.js 2025-10-25 19:32:51.000000000 +0000 @@ -21,24 +21,20 @@ */ // Code imported from main code base and exposed as injectable scriptlets -import { ArglistParser } from '../arglist-parser.js'; - +import { ArglistParser as __ArglistParser__ } from '../arglist-parser.js'; +import { JSONPath as __JSONPath__ } from '../jsonpath.js'; import { registerScriptlet } from './base.js'; /******************************************************************************/ +export const ArglistParser = __ArglistParser__; + registerScriptlet(ArglistParser, { name: 'arglist-parser.fn', }); -/******************************************************************************/ +export const JSONPath = __JSONPath__; -export function createArglistParser(...args) { - return new ArglistParser(...args); -} -registerScriptlet(createArglistParser, { - name: 'create-arglist-parser.fn', - dependencies: [ - ArglistParser, - ], +registerScriptlet(JSONPath, { + name: 'jsonpath.fn', }); diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/stack-trace.js ublock-origin-1.67.0+dfsg/src/js/resources/stack-trace.js --- ublock-origin-1.62.0+dfsg/src/js/resources/stack-trace.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/stack-trace.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,148 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2019-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock + +*/ + +import { getExceptionTokenFn } from './utils.js'; +import { registerScriptlet } from './base.js'; +import { safeSelf } from './safe-self.js'; + +/******************************************************************************/ + +export function matchesStackTraceFn( + needleDetails, + logLevel = '' +) { + const safe = safeSelf(); + const exceptionToken = getExceptionTokenFn(); + const error = new safe.Error(exceptionToken); + const docURL = new URL(self.location.href); + docURL.hash = ''; + // Normalize stack trace + const reLine = /(.*?@)?(\S+)(:\d+):\d+\)?$/; + const lines = []; + for ( let line of safe.String_split.call(error.stack, /[\n\r]+/) ) { + if ( line.includes(exceptionToken) ) { continue; } + line = line.trim(); + const match = safe.RegExp_exec.call(reLine, line); + if ( match === null ) { continue; } + let url = match[2]; + if ( url.startsWith('(') ) { url = url.slice(1); } + if ( url === docURL.href ) { + url = 'inlineScript'; + } else if ( url.startsWith('') ) { + url = 'injectedScript'; + } + let fn = match[1] !== undefined + ? match[1].slice(0, -1) + : line.slice(0, match.index).trim(); + if ( fn.startsWith('at') ) { fn = fn.slice(2).trim(); } + let rowcol = match[3]; + lines.push(' ' + `${fn} ${url}${rowcol}:1`.trim()); + } + lines[0] = `stackDepth:${lines.length-1}`; + const stack = lines.join('\t'); + const r = needleDetails.matchAll !== true && + safe.testPattern(needleDetails, stack); + if ( + logLevel === 'all' || + logLevel === 'match' && r || + logLevel === 'nomatch' && !r + ) { + safe.uboLog(stack.replace(/\t/g, '\n')); + } + return r; +} +registerScriptlet(matchesStackTraceFn, { + name: 'matches-stack-trace.fn', + dependencies: [ + getExceptionTokenFn, + safeSelf, + ], +}); + +/******************************************************************************/ + +function abortOnStackTrace( + chain = '', + needle = '' +) { + if ( typeof chain !== 'string' ) { return; } + const safe = safeSelf(); + const needleDetails = safe.initPattern(needle, { canNegate: true }); + const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); + if ( needle === '' ) { extraArgs.log = 'all'; } + const makeProxy = function(owner, chain) { + const pos = chain.indexOf('.'); + if ( pos === -1 ) { + let v = owner[chain]; + Object.defineProperty(owner, chain, { + get: function() { + const log = safe.logLevel > 1 ? 'all' : 'match'; + if ( matchesStackTraceFn(needleDetails, log) ) { + throw new ReferenceError(getExceptionTokenFn()); + } + return v; + }, + set: function(a) { + const log = safe.logLevel > 1 ? 'all' : 'match'; + if ( matchesStackTraceFn(needleDetails, log) ) { + throw new ReferenceError(getExceptionTokenFn()); + } + v = a; + }, + }); + return; + } + const prop = chain.slice(0, pos); + let v = owner[prop]; + chain = chain.slice(pos + 1); + if ( v ) { + makeProxy(v, chain); + return; + } + const desc = Object.getOwnPropertyDescriptor(owner, prop); + if ( desc && desc.set !== undefined ) { return; } + Object.defineProperty(owner, prop, { + get: function() { return v; }, + set: function(a) { + v = a; + if ( a instanceof Object ) { + makeProxy(a, chain); + } + } + }); + }; + const owner = window; + makeProxy(owner, chain); +} +registerScriptlet(abortOnStackTrace, { + name: 'abort-on-stack-trace.js', + aliases: [ + 'aost.js', + ], + dependencies: [ + getExceptionTokenFn, + matchesStackTraceFn, + safeSelf, + ], +}); + +/******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/src/js/resources/utils.js ublock-origin-1.67.0+dfsg/src/js/resources/utils.js --- ublock-origin-1.62.0+dfsg/src/js/resources/utils.js 1970-01-01 00:00:00.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/resources/utils.js 2025-10-25 19:32:51.000000000 +0000 @@ -0,0 +1,192 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2019-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock + +*/ + +import { registerScriptlet } from './base.js'; +import { safeSelf } from './safe-self.js'; + +// Externally added to the private namespace in which scriptlets execute. +/* global scriptletGlobals */ + +/******************************************************************************/ + +export function getRandomTokenFn() { + const safe = safeSelf(); + return safe.String_fromCharCode(Date.now() % 26 + 97) + + safe.Math_floor(safe.Math_random() * 982451653 + 982451653).toString(36); +} +registerScriptlet(getRandomTokenFn, { + name: 'get-random-token.fn', + dependencies: [ + safeSelf, + ], +}); + +/******************************************************************************/ + +export function getExceptionTokenFn() { + const token = getRandomTokenFn(); + const oe = self.onerror; + self.onerror = function(msg, ...args) { + if ( typeof msg === 'string' && msg.includes(token) ) { return true; } + if ( oe instanceof Function ) { + return oe.call(this, msg, ...args); + } + }.bind(); + return token; +} +registerScriptlet(getExceptionTokenFn, { + name: 'get-exception-token.fn', + dependencies: [ + getRandomTokenFn, + ], +}); + +/******************************************************************************/ + +export function parsePropertiesToMatchFn(propsToMatch, implicit = '') { + const safe = safeSelf(); + const needles = new Map(); + if ( propsToMatch === undefined || propsToMatch === '' ) { return needles; } + const options = { canNegate: true }; + for ( const needle of safe.String_split.call(propsToMatch, /\s+/) ) { + let [ prop, pattern ] = safe.String_split.call(needle, ':'); + if ( prop === '' ) { continue; } + if ( pattern !== undefined && /[^$\w -]/.test(prop) ) { + prop = `${prop}:${pattern}`; + pattern = undefined; + } + if ( pattern !== undefined ) { + needles.set(prop, safe.initPattern(pattern, options)); + } else if ( implicit !== '' ) { + needles.set(implicit, safe.initPattern(prop, options)); + } + } + return needles; +} +registerScriptlet(parsePropertiesToMatchFn, { + name: 'parse-properties-to-match.fn', + dependencies: [ + safeSelf, + ], +}); + +/******************************************************************************/ + +export function matchObjectPropertiesFn(propNeedles, ...objs) { + const safe = safeSelf(); + const matched = []; + for ( const obj of objs ) { + if ( obj instanceof Object === false ) { continue; } + for ( const [ prop, details ] of propNeedles ) { + let value = obj[prop]; + if ( value === undefined ) { continue; } + if ( typeof value !== 'string' ) { + try { value = safe.JSON_stringify(value); } + catch { } + if ( typeof value !== 'string' ) { continue; } + } + if ( safe.testPattern(details, value) === false ) { return; } + matched.push(`${prop}: ${value}`); + } + } + return matched; +} +registerScriptlet(matchObjectPropertiesFn, { + name: 'match-object-properties.fn', + dependencies: [ + safeSelf, + ], +}); + +/******************************************************************************/ + +// Reference: +// https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-scriptlets.md#prevent-xhr +// +// Added `trusted` argument to allow for returning arbitrary text. Can only +// be used through scriptlets requiring trusted source. + +export function generateContentFn(trusted, directive) { + const safe = safeSelf(); + const randomize = len => { + const chunks = []; + let textSize = 0; + do { + const s = safe.Math_random().toString(36).slice(2); + chunks.push(s); + textSize += s.length; + } + while ( textSize < len ); + return chunks.join(' ').slice(0, len); + }; + if ( directive === 'true' ) { + return randomize(10); + } + if ( directive === 'emptyObj' ) { + return '{}'; + } + if ( directive === 'emptyArr' ) { + return '[]'; + } + if ( directive === 'emptyStr' ) { + return ''; + } + if ( directive.startsWith('length:') ) { + const match = /^length:(\d+)(?:-(\d+))?$/.exec(directive); + if ( match === null ) { return ''; } + const min = parseInt(match[1], 10); + const extent = safe.Math_max(parseInt(match[2], 10) || 0, min) - min; + const len = safe.Math_min(min + extent * safe.Math_random(), 500000); + return randomize(len | 0); + } + if ( directive.startsWith('war:') ) { + if ( scriptletGlobals.warOrigin === undefined ) { return ''; } + return new Promise(resolve => { + const warOrigin = scriptletGlobals.warOrigin; + const warName = directive.slice(4); + const fullpath = [ warOrigin, '/', warName ]; + const warSecret = scriptletGlobals.warSecret; + if ( warSecret !== undefined ) { + fullpath.push('?secret=', warSecret); + } + const warXHR = new safe.XMLHttpRequest(); + warXHR.responseType = 'text'; + warXHR.onloadend = ev => { + resolve(ev.target.responseText || ''); + }; + warXHR.open('GET', fullpath.join('')); + warXHR.send(); + }).catch(( ) => ''); + } + if ( trusted ) { + return directive; + } + return ''; +} +registerScriptlet(generateContentFn, { + name: 'generate-content.fn', + dependencies: [ + safeSelf, + ], +}); + +/******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/src/js/reverselookup-worker.js ublock-origin-1.67.0+dfsg/src/js/reverselookup-worker.js --- ublock-origin-1.62.0+dfsg/src/js/reverselookup-worker.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/reverselookup-worker.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ let listEntries = Object.create(null); @@ -75,9 +73,10 @@ continue; } lists.push({ - assetKey: assetKey, + assetKey, title: entry.title, - supportURL: entry.supportURL + supportURL: entry.supportURL, + reason: entry.reason, }); break; } @@ -117,12 +116,13 @@ const exception = prefix.charAt(1) === '@'; const selector = details.rawFilter.slice(prefix.length); const isHtmlFilter = prefix.endsWith('^'); - const hostname = details.hostname; + const url = new URL(details.url || 'about:blank'); + const { hostname, pathname } = url; // The longer the needle, the lower the number of false positives. // https://github.com/uBlockOrigin/uBlock-issues/issues/1139 // Mind that there is no guarantee a selector has `\w` characters. - const needle = selector.match(/\w+|\*/g).reduce(function(a, b) { + const needle = (details.needle || selector).match(/\w+|\*/g).reduce(function(a, b) { return a.length > b.length ? a : b; }); @@ -149,17 +149,43 @@ } } - const hostnameMatches = hn => { - if ( hn === '' ) { return true; } - if ( hn.charCodeAt(0) === 0x2F /* / */ ) { - return (new RegExp(hn.slice(1,-1))).test(hostname); - } - if ( reHostname.test(hn) ) { return true; } + const hostnameTargetMatchesHostname = target => { + if ( target === '' ) { return true; } + if ( reHostname.test(target) ) { return true; } if ( reEntity === undefined ) { return false; } - if ( reEntity.test(hn) ) { return true; } + if ( reEntity.test(target) ) { return true; } return false; }; + const regexTargetMatchesHostname = target => { + return (new RegExp(target)).test(hostname); + }; + + const regexTargetMatchesURL = target => { + const pathPos = target.indexOf('\\/'); + if ( pathPos === -1 ) { + return regexTargetMatchesHostname(target); + } + return regexTargetMatchesHostname(`${target.slice(1, pathPos)}$`) && + (new RegExp(`^${target.slice(pathPos, -1)}`)).test(pathname); + }; + + const pathTargetMatchesURL = target => { + const pathPos = target.indexOf('/'); + return hostnameTargetMatchesHostname(target.slice(0, pathPos)) && + pathname.startsWith(target.slice(pathPos)); + }; + + const targetMatchesURL = target => { + if ( target.charCodeAt(0) === 0x2F /* / */ ) { + return regexTargetMatchesURL(target.slice(1, -1)); + } + if ( target.includes('/') ) { + return pathTargetMatchesURL(target); + } + return hostnameTargetMatchesHostname(target); + }; + const response = Object.create(null); for ( const assetKey in listEntries ) { @@ -212,19 +238,27 @@ case 8: // HTML filtering // Response header filtering + /* fallthrough */ case 64: { - if ( exception !== ((fargs[2] & 0b001) !== 0) ) { break; } - const isProcedural = (fargs[2] & 0b010) !== 0; + if ( exception !== (fargs[2].charCodeAt(0) === 0x2D /* - */) ) { break; } + const candidate = fargs[2].slice(1); + if ( /^responseheader\(.+\)$/.test(selector) ) { + if ( candidate !== needle ) { break; } + if ( targetMatchesURL(fargs[1]) === false ) { break; } + found = fargs[1] + prefix + selector; + break; + } + const isProcedural = candidate.charCodeAt(0) === 0x7B /* { */; if ( - isProcedural === false && fargs[3] !== selector || - isProcedural && JSON.parse(fargs[3]).raw !== selector + isProcedural === false && candidate !== selector || + isProcedural && JSON.parse(candidate).raw !== selector ) { break; } - if ( hostnameMatches(fargs[1]) === false ) { break; } + if ( targetMatchesURL(fargs[1]) === false ) { break; } // https://www.reddit.com/r/uBlockOrigin/comments/d6vxzj/ // Ignore match if specific cosmetic filters are disabled - if ( + if ( filterType === 8 && exception === false && details.ignoreSpecific @@ -235,14 +269,18 @@ break; } // Scriptlet injection - case 32: - if ( exception !== ((fargs[2] & 0b001) !== 0) ) { break; } - if ( fargs[3] !== details.compiled ) { break; } - if ( hostnameMatches(fargs[1]) ) { + case 32: { + if ( exception !== (fargs[2].charCodeAt(0) === 0x2D /* - */) ) { break; } + const candidate = fargs[2].slice(1); + if ( candidate !== details.needle ) { break; } + if (targetMatchesURL(fargs[1]) ) { found = fargs[1] + prefix + selector; } break; } + default: + break; + } if ( found !== undefined ) { if ( response[found] === undefined ) { response[found] = []; diff -Nru ublock-origin-1.62.0+dfsg/src/js/reverselookup.js ublock-origin-1.67.0+dfsg/src/js/reverselookup.js --- ublock-origin-1.62.0+dfsg/src/js/reverselookup.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/reverselookup.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,20 +19,15 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - -import staticNetFilteringEngine from './static-net-filtering.js'; -import µb from './background.js'; -import { CompiledListWriter } from './static-filtering-io.js'; -import { i18n$ } from './i18n.js'; import * as sfp from './static-filtering-parser.js'; - import { domainFromHostname, hostnameFromURI, } from './uri-utils.js'; +import { CompiledListWriter } from './static-filtering-io.js'; +import { i18n$ } from './i18n.js'; +import staticNetFilteringEngine from './static-net-filtering.js'; +import µb from './background.js'; /******************************************************************************/ @@ -98,7 +93,7 @@ }; for ( const listKey in µb.availableFilterLists ) { - if ( µb.availableFilterLists.hasOwnProperty(listKey) === false ) { + if ( Object.hasOwn(µb.availableFilterLists, listKey) === false ) { continue; } const entry = µb.availableFilterLists[listKey]; @@ -172,16 +167,18 @@ nativeCssHas: vAPI.webextFlavor.env.includes('native_css_has'), }); parser.parse(details.rawFilter); - let compiled; + let needle; if ( parser.isScriptletFilter() ) { - compiled = JSON.stringify(parser.getScriptletArgs()); + needle = JSON.stringify(parser.getScriptletArgs()); + } else if ( parser.isResponseheaderFilter() ) { + needle = parser.getResponseheaderName(); } worker.postMessage({ what: 'fromExtendedFilter', id, + url: details.url, domain: domainFromHostname(hostname), - hostname, ignoreGeneric: staticNetFilteringEngine.matchRequestReverse( 'generichide', @@ -193,7 +190,7 @@ details.url ) === 2, rawFilter: details.rawFilter, - compiled, + needle, }); return new Promise(resolve => { @@ -211,13 +208,11 @@ /******************************************************************************/ -const staticFilteringReverseLookup = { +export const staticFilteringReverseLookup = { fromNetFilter, fromExtendedFilter, resetLists, shutdown: stopWorker }; -export default staticFilteringReverseLookup; - /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/src/js/s14e-serializer.js ublock-origin-1.67.0+dfsg/src/js/s14e-serializer.js --- ublock-origin-1.62.0+dfsg/src/js/s14e-serializer.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/s14e-serializer.js 2025-10-25 19:32:51.000000000 +0000 @@ -306,9 +306,6 @@ options.compressThreshold <= s.length ); -const hasOwnProperty = (o, p) => - Object.prototype.hasOwnProperty.call(o, p); - /******************************************************************************* * * A large Uint is always a positive integer (can be zero), assumed to be @@ -1155,7 +1152,7 @@ export const setConfig = config => { for ( const key in Object.keys(config) ) { - if ( hasOwnProperty(defaultConfig, key) === false ) { continue; } + if ( Object.hasOwn(defaultConfig, key) === false ) { continue; } const val = config[key]; if ( typeof val !== typeof defaultConfig[key] ) { continue; } if ( (validateConfig[key])(val) === false ) { continue; } @@ -1422,8 +1419,14 @@ break; } case THREAD_DESERIALIZE: { - const result = deserialize(msg.data); - globalThis.postMessage({ id: msg.id, size: msg.size, result }); + let result; + try { + result = deserialize(msg.data); + } catch(ex) { + console.error(ex); + } finally { + globalThis.postMessage({ id: msg.id, size: msg.size, result }); + } break; } default: diff -Nru ublock-origin-1.62.0+dfsg/src/js/scriptlet-filtering-core.js ublock-origin-1.67.0+dfsg/src/js/scriptlet-filtering-core.js --- ublock-origin-1.62.0+dfsg/src/js/scriptlet-filtering-core.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/scriptlet-filtering-core.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,24 +19,19 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - -import { redirectEngine as reng } from './redirect-engine.js'; import { StaticExtFilteringHostnameDB } from './static-ext-filtering-db.js'; +import { entityFromHostname } from './uri-utils.js'; +import { redirectEngine as reng } from './redirect-engine.js'; /******************************************************************************/ -// Increment when internal representation changes -const VERSION = 1; - -const $scriptlets = new Set(); -const $exceptions = new Set(); -const $mainWorldMap = new Map(); -const $isolatedWorldMap = new Map(); - -/******************************************************************************/ +// For debugging convenience: all the top function calls will appear +// at the bottom of a generated content script +const codeSorter = (a, b) => { + if ( a.startsWith('try') ) { return 1; } + if ( b.startsWith('try') ) { return -1; } + return 0; +}; const normalizeRawFilter = (parser, sourceIsTrusted = false) => { const args = parser.getScriptletArgs(); @@ -62,7 +57,12 @@ const details = reng.contentFromName(token, 'text/javascript'); if ( details === undefined ) { return; } const targetWorldMap = details.world !== 'ISOLATED' ? mainMap : isolatedMap; - const content = patchScriptlet(details.js, args.slice(1)); + const match = /^function\s+([^(\s]+)\s*\(/.exec(details.js); + const fname = match && match[1]; + const content = patchScriptlet(fname, details.js, args.slice(1)); + if ( fname ) { + targetWorldMap.set(token, details.js); + } const dependencies = details.dependencies || []; while ( dependencies.length !== 0 ) { const token = dependencies.shift(); @@ -76,22 +76,21 @@ } targetWorldMap.set(rawToken, [ 'try {', - '// >>>> scriptlet start', - content, - '// <<<< scriptlet end', + `\t${content}`, '} catch (e) {', - debug ? 'console.error(e);' : '', + debug ? '\tconsole.error(e);' : '', '}', ].join('\n')); }; // Fill-in scriptlet argument placeholders. -const patchScriptlet = (content, arglist) => { - if ( content.startsWith('function') && content.endsWith('}') ) { - content = `(${content})({{args}});`; - } - for ( let i = 0; i < arglist.length; i++ ) { - content = content.replace(`{{${i+1}}}`, arglist[i]); +const patchScriptlet = (fname, content, arglist) => { + if ( fname ) { + content = `${fname}({{args}});`; + } else { + for ( let i = 0; i < arglist.length; i++ ) { + content = content.replace(`{{${i+1}}}`, arglist[i]); + } } return content.replace('{{args}}', JSON.stringify(arglist).slice(1,-1).replace(/\$/g, '$$$') @@ -106,10 +105,10 @@ return `'${s.replace(/'/g, "\\'")}'`; }; -const decompile = json => { +const decompile = (json, isException) => { + const prefix = isException ? '#@#' : '##'; const args = JSON.parse(json); - if ( args.length === 0 ) { return '+js()'; } - return `+js(${args.map(s => requote(s)).join(', ')})`; + return `${prefix}+js(${args.map(s => requote(s)).join(', ')})`; }; /******************************************************************************/ @@ -118,7 +117,7 @@ constructor() { this.acceptedCount = 0; this.discardedCount = 0; - this.scriptletDB = new StaticExtFilteringHostnameDB(1, VERSION); + this.scriptletDB = new StaticExtFilteringHostnameDB(); this.duplicates = new Set(); } @@ -155,7 +154,7 @@ if ( parser.hasOptions() === false ) { if ( isException ) { - writer.push([ 32, '', 1, normalized ]); + writer.push([ 32, '', `-${normalized}` ]); } return; } @@ -166,14 +165,8 @@ for ( const { hn, not, bad } of parser.getExtFilterDomainIterator() ) { if ( bad ) { continue; } - let kind = 0; - if ( isException ) { - if ( not ) { continue; } - kind |= 1; - } else if ( not ) { - kind |= 1; - } - writer.push([ 32, hn, kind, normalized ]); + const prefix = ((isException ? 1 : 0) ^ (not ? 1 : 0)) ? '-' : '+'; + writer.push([ 32, hn, `${prefix}${normalized}` ]); } } @@ -190,8 +183,7 @@ } this.duplicates.add(fingerprint); const args = reader.args(); - if ( args.length < 4 ) { continue; } - this.scriptletDB.store(args[1], args[2], args[3]); + this.scriptletDB.store(args[1], args[2]); } } @@ -200,8 +192,6 @@ } fromSelfie(selfie) { - if ( typeof selfie !== 'object' || selfie === null ) { return false; } - if ( selfie.version !== VERSION ) { return false; } this.scriptletDB.fromSelfie(selfie); return true; } @@ -209,55 +199,78 @@ retrieve(request, options = {}) { if ( this.scriptletDB.size === 0 ) { return; } - $scriptlets.clear(); - $exceptions.clear(); + const all = new Set(); + const { ancestors = [], domain, hostname } = request; - const { hostname } = request; - - this.scriptletDB.retrieve(hostname, [ $scriptlets, $exceptions ]); - const entity = request.entity !== '' - ? `${hostname.slice(0, -request.domain.length)}${request.entity}` - : '*'; - this.scriptletDB.retrieve(entity, [ $scriptlets, $exceptions ], 1); - if ( $scriptlets.size === 0 ) { return; } + this.scriptletDB.retrieveSpecifics(all, hostname); + const entity = entityFromHostname(hostname, domain); + this.scriptletDB.retrieveSpecifics(all, entity); + this.scriptletDB.retrieveSpecificsByRegex(all, hostname, request.url); + this.scriptletDB.retrieveGenerics(all); + const visitedAncestors = []; + for ( const ancestor of ancestors ) { + const { domain, hostname } = ancestor; + if ( visitedAncestors.includes(hostname) ) { continue; } + visitedAncestors.push(hostname); + this.scriptletDB.retrieveSpecifics(all, `${hostname}>>`); + const entity = entityFromHostname(hostname, domain); + if ( entity !== '' ) { + this.scriptletDB.retrieveSpecifics(all, `${entity}>>`); + } + } + if ( all.size === 0 ) { return; } // Wholly disable scriptlet injection? - if ( $exceptions.has('[]') ) { - return { filters: '#@#+js()' }; + if ( all.has('-[]') ) { + return { filters: [ '#@#+js()' ] }; } - for ( const token of $exceptions ) { - if ( $scriptlets.has(token) ) { - $scriptlets.delete(token); + // Split filters in different groups + const scriptlets = new Set(); + const exceptions = new Set(); + for ( const s of all ) { + if ( s.charCodeAt(0) === 0x2D /* - */ ) { continue; } + const selector = s.slice(1); + if ( all.has(`-${selector}`) ) { + exceptions.add(selector); } else { - $exceptions.delete(token); + scriptlets.add(selector); } } - for ( const token of $scriptlets ) { - lookupScriptlet(token, $mainWorldMap, $isolatedWorldMap, options.debug); + const mainWorldMap = new Map(); + const isolatedWorldMap = new Map(); + + for ( const token of scriptlets ) { + lookupScriptlet(token, mainWorldMap, isolatedWorldMap, options.debug); + } + + if ( scriptlets.size !== 0 ) { + if ( mainWorldMap.size === 0 ) { + if ( isolatedWorldMap.size === 0 ) { return; } + } } const mainWorldCode = []; - for ( const js of $mainWorldMap.values() ) { + for ( const js of mainWorldMap.values() ) { mainWorldCode.push(js); } + mainWorldCode.sort(codeSorter); const isolatedWorldCode = []; - for ( const js of $isolatedWorldMap.values() ) { + for ( const js of isolatedWorldMap.values() ) { isolatedWorldCode.push(js); } + isolatedWorldCode.sort(codeSorter); const scriptletDetails = { mainWorld: mainWorldCode.join('\n\n'), isolatedWorld: isolatedWorldCode.join('\n\n'), filters: [ - ...Array.from($scriptlets).map(s => `##${decompile(s)}`), - ...Array.from($exceptions).map(s => `#@#${decompile(s)}`), - ].join('\n'), + ...Array.from(scriptlets).map(a => decompile(a, false)), + ...Array.from(exceptions).map(a => decompile(a, true)), + ], }; - $mainWorldMap.clear(); - $isolatedWorldMap.clear(); const scriptletGlobals = options.scriptletGlobals || {}; @@ -265,6 +278,8 @@ scriptletGlobals.canDebug = true; } + const scriptletGlobalsJSON = JSON.stringify(scriptletGlobals, null, 4); + return { mainWorld: scriptletDetails.mainWorld === '' ? '' : [ '(function() {', @@ -273,7 +288,7 @@ options.debugScriptlets ? 'debugger;' : ';', '', // For use by scriptlets to share local data among themselves - `const scriptletGlobals = ${JSON.stringify(scriptletGlobals, null, 4)}`, + `const scriptletGlobals = ${scriptletGlobalsJSON};`, '', scriptletDetails.mainWorld, '', @@ -287,7 +302,7 @@ options.debugScriptlets ? 'debugger;' : ';', '', // For use by scriptlets to share local data among themselves - `const scriptletGlobals = ${JSON.stringify(scriptletGlobals, null, 4)}`, + `const scriptletGlobals = ${scriptletGlobalsJSON};`, '', scriptletDetails.isolatedWorld, '', diff -Nru ublock-origin-1.62.0+dfsg/src/js/scriptlet-filtering.js ublock-origin-1.67.0+dfsg/src/js/scriptlet-filtering.js --- ublock-origin-1.62.0+dfsg/src/js/scriptlet-filtering.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/scriptlet-filtering.js 2025-10-25 19:32:51.000000000 +0000 @@ -23,7 +23,6 @@ import { domainFromHostname, - entityFromDomain, hostnameFromURI, } from './uri-utils.js'; @@ -38,10 +37,9 @@ /******************************************************************************/ -const contentScriptRegisterer = new (class { - constructor() { - this.hostnameToDetails = new Map(); - } +const contentScriptRegisterer = { + id: 1, + hostnameToDetails: new Map(), register(hostname, code) { if ( browser.contentScripts === undefined ) { return false; } if ( hostname === '' ) { return false; } @@ -50,9 +48,10 @@ if ( code === details.code ) { return details.handle instanceof Promise === false; } - details.handle.unregister(); + this.unregisterHandle(details.handle); this.hostnameToDetails.delete(hostname); } + const id = this.id++; const promise = browser.contentScripts.register({ js: [ { code } ], allFrames: true, @@ -60,14 +59,16 @@ matchAboutBlank: true, runAt: 'document_start', }).then(handle => { - this.hostnameToDetails.set(hostname, { handle, code }); - return handle; + const details = this.hostnameToDetails.get(hostname); + if ( details === undefined ) { return; } + if ( details.id !== id ) { return; } + details.handle = handle; }).catch(( ) => { this.hostnameToDetails.delete(hostname); }); - this.hostnameToDetails.set(hostname, { handle: promise, code }); + this.hostnameToDetails.set(hostname, { id, handle: promise, code }); return false; - } + }, unregister(hostname) { if ( hostname === '' ) { return; } if ( this.hostnameToDetails.size === 0 ) { return; } @@ -75,7 +76,7 @@ if ( details === undefined ) { return; } this.hostnameToDetails.delete(hostname); this.unregisterHandle(details.handle); - } + }, flush(hostname) { if ( hostname === '' ) { return; } if ( hostname === '*' ) { return this.reset(); } @@ -85,14 +86,14 @@ if ( pos !== 0 && hn.charCodeAt(pos-1) !== 0x2E /* . */ ) { continue; } this.unregister(hn); } - } + }, reset() { if ( this.hostnameToDetails.size === 0 ) { return; } for ( const details of this.hostnameToDetails.values() ) { this.unregisterHandle(details.handle); } this.hostnameToDetails.clear(); - } + }, unregisterHandle(handle) { if ( handle instanceof Promise ) { handle.then(handle => { @@ -101,8 +102,8 @@ } else { handle.unregister(); } - } -})(); + }, +}; /******************************************************************************/ @@ -166,7 +167,7 @@ }; bcSecret.postMessage('iamready!'); self.uBO_bcSecret = bcSecret; - } catch(_) { + } catch { } }.toString(), ')(', @@ -316,7 +317,7 @@ filters: scriptletDetails.filters, }; - if ( request.nocache !== true ) { + if ( hostname !== '' && request.nocache !== true ) { this.scriptletCache.add(hostname, cachedScriptletDetails); } @@ -335,7 +336,7 @@ url: details.url, hostname, domain, - entity: entityFromDomain(domain), + ancestors: details.ancestors, }); if ( scriptletDetails === undefined ) { contentScriptRegisterer.unregister(hostname); @@ -371,17 +372,16 @@ toLogger(request, details) { if ( details === undefined ) { return; } if ( logger.enabled !== true ) { return; } - if ( typeof details.filters !== 'string' ) { return; } - const fctxt = µb.filteringContext + if ( Array.isArray(details.filters) === false ) { return; } + µb.filteringContext .duplicate() .fromTabId(request.tabId) .setRealm('extended') .setType('scriptlet') .setURL(request.url) - .setDocOriginFromURL(request.url); - for ( const raw of details.filters.split('\n') ) { - fctxt.setFilter({ source: 'extended', raw }).toLogger(); - } + .setDocOriginFromURL(request.url) + .setFilter(details.filters.map(a => ({ source: 'extended', raw: a }))) + .toLogger(); } } diff -Nru ublock-origin-1.62.0+dfsg/src/js/scriptlets/cosmetic-logger.js ublock-origin-1.67.0+dfsg/src/js/scriptlets/cosmetic-logger.js --- ublock-origin-1.62.0+dfsg/src/js/scriptlets/cosmetic-logger.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/scriptlets/cosmetic-logger.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,10 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -/* globals browser */ - -'use strict'; - /******************************************************************************/ (( ) => { @@ -53,7 +49,7 @@ try { return context.querySelector(selector) !== null; } - catch(ex) { + catch { } return false; } @@ -65,7 +61,7 @@ try { return context.matches(safeSelector); } - catch(ex) { + catch { } return false; } @@ -77,7 +73,7 @@ try { return context.querySelector(safeSelector); } - catch(ex) { + catch { } return null; } diff -Nru ublock-origin-1.62.0+dfsg/src/js/scriptlets/cosmetic-off.js ublock-origin-1.67.0+dfsg/src/js/scriptlets/cosmetic-off.js --- ublock-origin-1.62.0+dfsg/src/js/scriptlets/cosmetic-off.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/scriptlets/cosmetic-off.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ if ( typeof vAPI === 'object' && vAPI.domFilterer ) { diff -Nru ublock-origin-1.62.0+dfsg/src/js/scriptlets/cosmetic-on.js ublock-origin-1.67.0+dfsg/src/js/scriptlets/cosmetic-on.js --- ublock-origin-1.62.0+dfsg/src/js/scriptlets/cosmetic-on.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/scriptlets/cosmetic-on.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ if ( typeof vAPI === 'object' && vAPI.domFilterer ) { diff -Nru ublock-origin-1.62.0+dfsg/src/js/scriptlets/cosmetic-report.js ublock-origin-1.67.0+dfsg/src/js/scriptlets/cosmetic-report.js --- ublock-origin-1.62.0+dfsg/src/js/scriptlets/cosmetic-report.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/scriptlets/cosmetic-report.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ (( ) => { @@ -40,7 +38,7 @@ try { return document.querySelector(selector) !== null; } - catch(ex) { + catch { } return false; }; @@ -52,7 +50,7 @@ try { return document.querySelector(safeSelector); } - catch(ex) { + catch { } return null; }; @@ -127,8 +125,8 @@ } } -if ( typeof self.uBO_scriptletsInjected === 'string' ) { - matchedSelectors.push(...self.uBO_scriptletsInjected.split('\n')); +if ( self.uBO_scriptletsInjected !== undefined ) { + matchedSelectors.push(...self.uBO_scriptletsInjected); } if ( matchedSelectors.length === 0 ) { return; } diff -Nru ublock-origin-1.62.0+dfsg/src/js/scriptlets/dom-inspector.js ublock-origin-1.67.0+dfsg/src/js/scriptlets/dom-inspector.js --- ublock-origin-1.62.0+dfsg/src/js/scriptlets/dom-inspector.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/scriptlets/dom-inspector.js 2025-10-25 19:32:51.000000000 +0000 @@ -431,7 +431,7 @@ // plain CSS selector try { return context.querySelectorAll(selector); - } catch (ex) { + } catch { } return []; }; @@ -443,7 +443,7 @@ let nodes; try { nodes = document.querySelectorAll(matches[1]); - } catch(ex) { + } catch { nodes = []; } for ( const node of nodes ) { @@ -772,7 +772,7 @@ if ( toLoggerPort === undefined ) { return; } try { toLoggerPort.postMessage(msg); - } catch(_) { + } catch { shutdownInspector(); } }; diff -Nru ublock-origin-1.62.0+dfsg/src/js/scriptlets/dom-survey-elements.js ublock-origin-1.67.0+dfsg/src/js/scriptlets/dom-survey-elements.js --- ublock-origin-1.62.0+dfsg/src/js/scriptlets/dom-survey-elements.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/scriptlets/dom-survey-elements.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ // https://github.com/uBlockOrigin/uBlock-issues/issues/756 diff -Nru ublock-origin-1.62.0+dfsg/src/js/scriptlets/dom-survey-scripts.js ublock-origin-1.67.0+dfsg/src/js/scriptlets/dom-survey-scripts.js --- ublock-origin-1.62.0+dfsg/src/js/scriptlets/dom-survey-scripts.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/scriptlets/dom-survey-scripts.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ // Scriptlets to count the number of script tags in a document. diff -Nru ublock-origin-1.62.0+dfsg/src/js/scriptlets/epicker.js ublock-origin-1.67.0+dfsg/src/js/scriptlets/epicker.js --- ublock-origin-1.62.0+dfsg/src/js/scriptlets/epicker.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/scriptlets/epicker.js 2025-10-25 19:32:51.000000000 +0000 @@ -52,7 +52,7 @@ if ( node !== null ) { try { return node.querySelectorAll(selector); - } catch (e) { + } catch { } } return []; @@ -672,8 +672,7 @@ let reFilter = null; try { reFilter = new RegExp(reStr, 'i'); - } - catch (e) { + } catch { return out; } @@ -727,8 +726,7 @@ elems = document.querySelectorAll( raw.replace(rePseudoElements, '') ); - } - catch (e) { + } catch { return; } const out = []; @@ -762,7 +760,7 @@ default: break; } - } catch(ex) { + } catch { return; } if ( !elems ) { return; } diff -Nru ublock-origin-1.62.0+dfsg/src/js/scriptlets/load-3p-css.js ublock-origin-1.67.0+dfsg/src/js/scriptlets/load-3p-css.js --- ublock-origin-1.62.0+dfsg/src/js/scriptlets/load-3p-css.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/scriptlets/load-3p-css.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ (( ) => { @@ -34,7 +32,7 @@ let loaded = false; try { loaded = sheet.rules.length !== 0; - } catch(ex) { + } catch { } if ( loaded ) { continue; } const link = sheet.ownerNode || null; diff -Nru ublock-origin-1.62.0+dfsg/src/js/scriptlets/load-large-media-all.js ublock-origin-1.67.0+dfsg/src/js/scriptlets/load-large-media-all.js --- ublock-origin-1.62.0+dfsg/src/js/scriptlets/load-large-media-all.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/scriptlets/load-large-media-all.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ (( ) => { diff -Nru ublock-origin-1.62.0+dfsg/src/js/scriptlets/noscript-spoof.js ublock-origin-1.67.0+dfsg/src/js/scriptlets/noscript-spoof.js --- ublock-origin-1.62.0+dfsg/src/js/scriptlets/noscript-spoof.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/scriptlets/noscript-spoof.js 2025-10-25 19:32:51.000000000 +0000 @@ -22,8 +22,6 @@ // Code below has been imported from uMatrix and modified to fit uBO: // https://github.com/gorhill/uMatrix/blob/3f8794dd899a05e066c24066c6c0a2515d5c60d2/src/js/contentscript.js#L464-L531 -'use strict'; - /******************************************************************************/ // https://github.com/gorhill/uMatrix/issues/232 @@ -35,6 +33,8 @@ const reMetaContent = /^\s*(\d+)\s*;\s*url=(?:"([^"]+)"|'([^']+)'|(.+))/i; const reSafeURL = /^https?:\/\//; + const reNoscript = /(^|[ >+~])noscript([ >+~]|$)/g; + const className = vAPI.sessionId; let redirectTimer; const autoRefresh = function(root) { @@ -46,43 +46,57 @@ let url; try { url = new URL(refreshURL, document.baseURI); - } catch(ex) { + } catch { return; } if ( reSafeURL.test(url.href) === false ) { return; } redirectTimer = setTimeout(( ) => { - location.assign(url.href); - }, - parseInt(match[1], 10) * 1000 + 1 - ); + location.assign(url.href); + }, parseInt(match[1], 10) * 1000 + 1); meta.parentNode.removeChild(meta); }; const morphNoscript = function(from) { + const fragment = new DocumentFragment(); + const inHead = from.closest('head'); if ( /^application\/(?:xhtml\+)?xml/.test(document.contentType) ) { - const to = document.createElement('span'); while ( from.firstChild !== null ) { - to.appendChild(from.firstChild); + fragment.append(from.firstChild); } - return to; + return fragment; } const parser = new DOMParser(); const doc = parser.parseFromString( - '' + from.textContent + '', + ``, 'text/html' ); - return document.adoptNode(doc.querySelector('span')); + for ( const elem of doc.querySelectorAll(inHead ? 'span > *' : 'span') ) { + fragment.append(document.adoptNode(elem)); + } + return fragment; }; for ( const noscript of noscripts ) { - const parent = noscript.parentNode; - if ( parent === null ) { continue; } - const span = morphNoscript(noscript); - span.style.setProperty('display', 'inline', 'important'); + const fragment = morphNoscript(noscript); if ( redirectTimer === undefined ) { - autoRefresh(span); + autoRefresh(fragment); + } + noscript.replaceWith(fragment); + } + + for ( const sheet of document.styleSheets ) { + try { + for ( const rule of sheet.cssRules ) { + if ( reNoscript.test(rule.selectorText) === false ) { continue; } + rule.selectorText = + rule.selectorText.replace(reNoscript, `$1span.${className}$2`); + } + } catch { } - parent.replaceChild(span, noscript); + } + + for ( const span of document.querySelectorAll(`.${className}`) ) { + span.style.setProperty('display', 'inline', 'important'); } })(); diff -Nru ublock-origin-1.62.0+dfsg/src/js/scriptlets/scriptlet-loglevel-1.js ublock-origin-1.67.0+dfsg/src/js/scriptlets/scriptlet-loglevel-1.js --- ublock-origin-1.62.0+dfsg/src/js/scriptlets/scriptlet-loglevel-1.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/scriptlets/scriptlet-loglevel-1.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ (( ) => { diff -Nru ublock-origin-1.62.0+dfsg/src/js/scriptlets/scriptlet-loglevel-2.js ublock-origin-1.67.0+dfsg/src/js/scriptlets/scriptlet-loglevel-2.js --- ublock-origin-1.62.0+dfsg/src/js/scriptlets/scriptlet-loglevel-2.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/scriptlets/scriptlet-loglevel-2.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ (( ) => { diff -Nru ublock-origin-1.62.0+dfsg/src/js/scriptlets/should-inject-contentscript.js ublock-origin-1.67.0+dfsg/src/js/scriptlets/should-inject-contentscript.js --- ublock-origin-1.62.0+dfsg/src/js/scriptlets/should-inject-contentscript.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/scriptlets/should-inject-contentscript.js 2025-10-25 19:32:51.000000000 +0000 @@ -32,7 +32,7 @@ self.requestIdleCallback(( ) => vAPI?.bootstrap?.()); } return status; - } catch(ex) { + } catch { } return true; })(); diff -Nru ublock-origin-1.62.0+dfsg/src/js/scriptlets/subscriber.js ublock-origin-1.67.0+dfsg/src/js/scriptlets/subscriber.js --- ublock-origin-1.62.0+dfsg/src/js/scriptlets/subscriber.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/scriptlets/subscriber.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,10 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -/* global HTMLDocument */ - -'use strict'; - /******************************************************************************/ // Injected into specific web pages, those which have been pre-selected @@ -70,7 +66,7 @@ title, }); return true; - } catch (_) { + } catch { } }; diff -Nru ublock-origin-1.62.0+dfsg/src/js/scriptlets/updater.js ublock-origin-1.67.0+dfsg/src/js/scriptlets/updater.js --- ublock-origin-1.62.0+dfsg/src/js/scriptlets/updater.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/scriptlets/updater.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,10 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -/* global HTMLDocument */ - -'use strict'; - /******************************************************************************/ // Injected into specific webpages, those which have been pre-selected @@ -75,7 +71,7 @@ auto, }); return true; - } catch (_) { + } catch { } } diff -Nru ublock-origin-1.62.0+dfsg/src/js/settings.js ublock-origin-1.67.0+dfsg/src/js/settings.js --- ublock-origin-1.62.0+dfsg/src/js/settings.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/settings.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,11 +19,9 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -import { i18n$ } from './i18n.js'; import { dom, qs$, qsa$ } from './dom.js'; import { setAccentColor, setTheme } from './theme.js'; +import { i18n$ } from './i18n.js'; /******************************************************************************/ @@ -69,7 +67,7 @@ throw 'Invalid'; } } - catch (e) { + catch { userData = undefined; } if ( userData === undefined ) { diff -Nru ublock-origin-1.62.0+dfsg/src/js/start.js ublock-origin-1.67.0+dfsg/src/js/start.js --- ublock-origin-1.62.0+dfsg/src/js/start.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/start.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,12 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -/* globals browser */ - -'use strict'; - -/******************************************************************************/ - import './vapi-common.js'; import './vapi-background.js'; import './vapi-background-ext.js'; @@ -39,27 +33,27 @@ import './ublock.js'; import './utils.js'; -import io from './assets.js'; -import µb from './background.js'; -import { filteringBehaviorChanged } from './broadcast.js'; -import cacheStorage from './cachestorage.js'; -import { ubolog } from './console.js'; -import contextMenu from './contextmenu.js'; -import { redirectEngine } from './redirect-engine.js'; -import staticFilteringReverseLookup from './reverselookup.js'; -import staticExtFilteringEngine from './static-ext-filtering.js'; -import staticNetFilteringEngine from './static-net-filtering.js'; -import webRequest from './traffic.js'; - import { permanentFirewall, - sessionFirewall, permanentSwitches, - sessionSwitches, permanentURLFiltering, + sessionFirewall, + sessionSwitches, sessionURLFiltering, } from './filtering-engines.js'; +import cacheStorage from './cachestorage.js'; +import contextMenu from './contextmenu.js'; +import { filteringBehaviorChanged } from './broadcast.js'; +import io from './assets.js'; +import { redirectEngine } from './redirect-engine.js'; +import staticExtFilteringEngine from './static-ext-filtering.js'; +import { staticFilteringReverseLookup } from './reverselookup.js'; +import staticNetFilteringEngine from './static-net-filtering.js'; +import { ubolog } from './console.js'; +import webRequest from './traffic.js'; +import µb from './background.js'; + /******************************************************************************/ let lastVersionInt = 0; @@ -163,13 +157,6 @@ return; } - // Remove cache items with obsolete names - if ( lastVersionInt < vAPI.app.intFromVersion('1.56.1b5') ) { - io.remove(`compiled/${µb.pslAssetKey}`); - io.remove('compiled/redirectEngine/resources'); - io.remove('selfie/main'); - } - // Since built-in resources may have changed since last version, we // force a reload of all resources. redirectEngine.invalidateResourcesSelfie(io); @@ -363,15 +350,15 @@ const toFetch = (from, fetched) => { for ( const k in from ) { - if ( from.hasOwnProperty(k) === false ) { continue; } + if ( Object.hasOwn(from, k) === false ) { continue; } fetched[k] = from[k]; } }; const fromFetch = (to, fetched) => { for ( const k in to ) { - if ( to.hasOwnProperty(k) === false ) { continue; } - if ( fetched.hasOwnProperty(k) === false ) { continue; } + if ( Object.hasOwn(to, k) === false ) { continue; } + if ( Object.hasOwn(fetched, k) === false ) { continue; } to[k] = fetched[k]; } }; diff -Nru ublock-origin-1.62.0+dfsg/src/js/static-dnr-filtering.js ublock-origin-1.67.0+dfsg/src/js/static-dnr-filtering.js --- ublock-origin-1.62.0+dfsg/src/js/static-dnr-filtering.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/static-dnr-filtering.js 2025-10-25 19:32:51.000000000 +0000 @@ -31,20 +31,7 @@ /******************************************************************************/ -// http://www.cse.yorku.ca/~oz/hash.html#djb2 -// Must mirror content script surveyor's version - -const hashFromStr = (type, s) => { - const len = s.length; - const step = len + 7 >>> 3; - let hash = (type << 5) + type ^ len; - for ( let i = 0; i < len; i += step ) { - hash = (hash << 5) + hash ^ s.charCodeAt(i); - } - return hash & 0xFFFFFF; -}; - -const isRegex = hn => hn.startsWith('/') && hn.endsWith('/'); +const isRegexOrPath = hn => hn.includes('/'); /******************************************************************************/ @@ -93,32 +80,19 @@ function addGenericCosmeticFilter(context, selector, isException) { if ( selector === undefined ) { return; } if ( selector.length <= 1 ) { return; } - if ( isException ) { - if ( context.genericCosmeticExceptions === undefined ) { - context.genericCosmeticExceptions = new Set(); - } - context.genericCosmeticExceptions.add(selector); - return; - } if ( selector.charCodeAt(0) === 0x7B /* '{' */ ) { return; } const key = keyFromSelector(selector); - if ( key === undefined ) { - if ( context.genericHighCosmeticFilters === undefined ) { - context.genericHighCosmeticFilters = new Set(); + if ( isException ) { + if ( context.genericCosmeticExceptions === undefined ) { + context.genericCosmeticExceptions = []; } - context.genericHighCosmeticFilters.add(selector); + context.genericCosmeticExceptions.push({ key, selector }); return; } - const type = key.charCodeAt(0); - const hash = hashFromStr(type, key.slice(1)); if ( context.genericCosmeticFilters === undefined ) { - context.genericCosmeticFilters = new Map(); - } - let bucket = context.genericCosmeticFilters.get(hash); - if ( bucket === undefined ) { - context.genericCosmeticFilters.set(hash, bucket = []); + context.genericCosmeticFilters = []; } - bucket.push(selector); + context.genericCosmeticFilters.push({ key, selector }); } /******************************************************************************/ @@ -138,7 +112,7 @@ for ( const { hn, not, bad } of parser.getExtFilterDomainIterator() ) { if ( bad ) { continue; } if ( exception ) { continue; } - if ( isRegex(hn) ) { continue; } + if ( isRegexOrPath(hn) ) { continue; } let details = context.scriptletFilters.get(argsToken); if ( details === undefined ) { context.scriptletFilters.set(argsToken, details = { args }); @@ -196,7 +170,7 @@ }; for ( const { hn, not, bad } of parser.getExtFilterDomainIterator() ) { if ( bad ) { continue; } - if ( isRegex(hn) ) { continue; } + if ( isRegexOrPath(hn) ) { continue; } if ( not ) { if ( rule.condition.excludedInitiatorDomains === undefined ) { rule.condition.excludedInitiatorDomains = []; @@ -247,37 +221,48 @@ }); return; } - let details = context.specificCosmeticFilters.get(compiled); + const matches = []; + const excludeMatches = []; for ( const { hn, not, bad } of parser.getExtFilterDomainIterator() ) { if ( bad ) { continue; } if ( not && exception ) { continue; } - if ( isRegex(hn) ) { continue; } - if ( details === undefined ) { - context.specificCosmeticFilters.set(compiled, details = {}); - } - if ( exception ) { - if ( details.excludeMatches === undefined ) { - details.excludeMatches = []; - } - details.excludeMatches.push(hn); - continue; + // TODO: Support regex- and path-based entries + if ( isRegexOrPath(hn) ) { continue; } + if ( not || exception ) { + excludeMatches.push(hn); + } else if ( hn !== '*' ) { + matches.push(hn); + } + } + // This should not happen + if ( matches.length === 0 && excludeMatches.length === 0 ) { return; } + // Only negated hostnames => generic cosmetic filter + if ( exception === false && matches.length === 0 && excludeMatches.length !== 0 ) { + addGenericCosmeticFilter(context, compiled, false); + } + const key = compiled.startsWith('{') === false && keyFromSelector(compiled); + let details = context.specificCosmeticFilters.get(compiled); + if ( details === undefined ) { + context.specificCosmeticFilters.set(compiled, details = {}); + if ( key ) { + details.key = key; } + } + if ( matches.length ) { if ( details.matches === undefined ) { details.matches = []; } - if ( details.matches.includes('*') ) { continue; } - if ( hn === '*' ) { + if ( matches.includes('*') ) { details.matches = [ '*' ]; - continue; + } else if ( details.matches.includes('*') === false ) { + details.matches.push(...matches); } - details.matches.push(hn); } - if ( details === undefined ) { return; } - if ( exception ) { return; } - if ( compiled.startsWith('{') ) { return; } - if ( details.matches === undefined || details.matches.includes('*') ) { - addGenericCosmeticFilter(context, compiled, false); - details.matches = undefined; + if ( excludeMatches.length ) { + if ( details.excludeMatches === undefined ) { + details.excludeMatches = []; + } + details.excludeMatches.push(...excludeMatches); } } @@ -459,6 +444,20 @@ mergeRules(rulesetMap, 'requestDomains'); mergeRules(rulesetMap, 'responseHeaders'); + // Convert back single-entry requestDomains into pattern-based filters + // https://github.com/uBlockOrigin/uBOL-home/issues/327 + // TODO: Remove when (if) Safari is changed to interpret requestDomains as + // in other browsers. + for ( const rule of rulesetMap.values() ) { + const { condition } = rule; + if ( condition?.requestDomains === undefined ) { continue; } + if ( condition.requestDomains.length !== 1 ) { continue; } + if ( condition.urlFilter !== undefined ) { continue; } + if ( condition.regexFilter !== undefined ) { continue; } + condition.urlFilter = `||${condition.requestDomains[0]}^`; + condition.requestDomains = undefined; + } + // Patch id const rulesetFinal = []; { @@ -483,6 +482,7 @@ async function dnrRulesetFromRawLists(lists, options = {}) { const context = Object.assign({}, options); + context.bad = options.networkBad; staticNetFilteringEngine.dnrFromCompiled('begin', context); context.extensionPaths = new Map(context.extensionPaths || []); const toLoad = []; @@ -497,8 +497,8 @@ await Promise.all(toLoad); const result = { network: staticNetFilteringEngine.dnrFromCompiled('end', context), - genericCosmetic: context.genericCosmeticFilters, - genericHighCosmetic: context.genericHighCosmeticFilters, + networkBad: context.bad, + genericCosmeticFilters: context.genericCosmeticFilters, genericCosmeticExceptions: context.genericCosmeticExceptions, specificCosmetic: context.specificCosmeticFilters, scriptlet: context.scriptletFilters, diff -Nru ublock-origin-1.62.0+dfsg/src/js/static-ext-filtering-db.js ublock-origin-1.67.0+dfsg/src/js/static-ext-filtering-db.js --- ublock-origin-1.62.0+dfsg/src/js/static-ext-filtering-db.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/static-ext-filtering-db.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,153 +19,226 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; +/******************************************************************************/ + +// example.com: domain => no slash +// example.com/toto: domain + path => slash +// /example\d+\.com$/: domain regex: no literal slash in regex +// /example\d+\.com\/toto\d+/: domain + path => literal slash in regex + +/******************************************************************************/ + +const naivePathnameFromURL = url => { + if ( typeof url !== 'string' ) { return; } + const hnPos = url.indexOf('://'); + if ( hnPos === -1 ) { return; } + const pathPos = url.indexOf('/', hnPos+3); + if ( pathPos === -1 ) { return; } + return url.slice(pathPos); +}; + +const extractSubTargets = target => { + const isRegex = target.charCodeAt(0) === 0x2F /* / */; + if ( isRegex === false ) { + const pathPos = target.indexOf('/'); + return { + isRegex, + hn: target.slice(0, pathPos), + pn: target.slice(pathPos), + }; + } + const pathPos = target.indexOf('\\/'); + if ( pathPos !== -1 ) { + return { + isRegex, + hn: `${target.slice(1, pathPos)}$`, + pn: `^${target.slice(pathPos, -1)}`, + }; + } + return { isRegex, hn: target.slice(1, -1) }; +}; /******************************************************************************/ -const StaticExtFilteringHostnameDB = class { - constructor(nBits, version = 0) { - this.version = version; - this.nBits = nBits; - this.strToIdMap = new Map(); - this.hostnameToSlotIdMap = new Map(); - this.regexToSlotIdMap = new Map(); - this.regexMap = new Map(); - // Array of integer pairs - this.hostnameSlots = []; - // Array of strings (selectors and pseudo-selectors) - this.strSlots = []; +export class StaticExtFilteringHostnameDB { + static VERSION = 1; + constructor() { this.size = 0; - this.cleanupTimer = vAPI.defer.create(( ) => { - this.strToIdMap.clear(); - }); } - store(hn, bits, s) { + #hostnameToStringListMap = new Map(); + #matcherMap = new Map(); + #hostnameToMatcherListMap = new Map(); + #strSlots = [ '' ]; // Array of strings (selectors and pseudo-selectors) + #matcherSlots = [ null ]; + #linkedLists = [ 0, 0 ];// Array of integer pairs + #regexMap = new Map(); + #strToSlotMap = new Map(); + #cleanupTimer = vAPI.defer.create(( ) => { + this.#strToSlotMap.clear(); + }); + + store(target, s) { this.size += 1; - let iStr = this.strToIdMap.get(s); + let iStr = this.#strToSlotMap.get(s); if ( iStr === undefined ) { - iStr = this.strSlots.length; - this.strSlots.push(s); - this.strToIdMap.set(s, iStr); - if ( this.cleanupTimer.ongoing() === false ) { + iStr = this.#strSlots.length; + this.#strSlots.push(s); + this.#strToSlotMap.set(s, iStr); + if ( this.#cleanupTimer.ongoing() === false ) { this.collectGarbage(true); } } - const strId = iStr << this.nBits | bits; - const hnIsNotRegex = hn.charCodeAt(0) !== 0x2F /* / */; - let iHn = hnIsNotRegex - ? this.hostnameToSlotIdMap.get(hn) - : this.regexToSlotIdMap.get(hn); - if ( iHn === undefined ) { - if ( hnIsNotRegex ) { - this.hostnameToSlotIdMap.set(hn, this.hostnameSlots.length); + if ( target.includes('/') ) { + return this.#storeMatcher(target, iStr); + } + const iList = this.#hostnameToStringListMap.get(target) ?? 0; + this.#hostnameToStringListMap.set(target, this.#linkedLists.length); + this.#linkedLists.push(iStr, iList); + } + + #storeMatcher(target, iStr) { + const iMatcher = this.#matcherMap.get(target) || + this.#matcherSlots.length; + if ( iMatcher === this.#matcherSlots.length ) { + const { isRegex, hn, pn } = extractSubTargets(target); + this.#matcherSlots.push({ isRegex, hn, pn, iList: 0 }); + this.#matcherMap.set(target, iMatcher); + if ( isRegex === false ) { + const iMatcherList = this.#hostnameToMatcherListMap.get(hn) ?? 0; + this.#hostnameToMatcherListMap.set(hn, this.#linkedLists.length); + this.#linkedLists.push(iMatcher, iMatcherList); } else { - this.regexToSlotIdMap.set(hn, this.hostnameSlots.length); + const iMatcherList = this.#hostnameToMatcherListMap.get('') ?? 0; + this.#hostnameToMatcherListMap.set('', this.#linkedLists.length); + this.#linkedLists.push(iMatcher, iMatcherList); } - this.hostnameSlots.push(strId, 0); - return; - } - // Add as last item. - while ( this.hostnameSlots[iHn+1] !== 0 ) { - iHn = this.hostnameSlots[iHn+1]; } - this.hostnameSlots[iHn+1] = this.hostnameSlots.length; - this.hostnameSlots.push(strId, 0); + const matcher = this.#matcherSlots[iMatcher]; + const iList = matcher.iList; + matcher.iList = this.#linkedLists.length; + this.#linkedLists.push(iStr, iList); } clear() { - this.hostnameToSlotIdMap.clear(); - this.regexToSlotIdMap.clear(); - this.hostnameSlots.length = 0; - this.strSlots.length = 0; - this.strToIdMap.clear(); - this.regexMap.clear(); + this.#hostnameToStringListMap.clear(); + this.#matcherMap.clear(); + this.#hostnameToMatcherListMap.clear(); + this.#strSlots = [ '' ]; + this.#matcherSlots = [ null ]; + this.#linkedLists = [ 0, 0 ]; + this.#regexMap.clear(); + this.#strToSlotMap.clear(); this.size = 0; } collectGarbage(later = false) { if ( later ) { - return this.cleanupTimer.onidle(5000, { timeout: 5000 }); + return this.#cleanupTimer.onidle(5000, { timeout: 5000 }); } - this.cleanupTimer.off(); - this.strToIdMap.clear(); + this.#cleanupTimer.off(); + this.#strToSlotMap.clear(); } - // modifiers = 0: all items - // modifiers = 1: only specific items - // modifiers = 2: only generic items - // modifiers = 3: only regex-based items - // - retrieve(hostname, out, modifiers = 0) { + retrieveSpecifics(out, hostname) { let hn = hostname; - if ( modifiers === 2 ) { hn = ''; } + if ( hn === '' ) { return; } for (;;) { - const hnSlot = this.hostnameToSlotIdMap.get(hn); - if ( hnSlot !== undefined ) { - this.retrieveFromSlot(hnSlot, out); + const iList = this.#hostnameToStringListMap.get(hn); + if ( iList !== undefined ) { + this.#retrieveFromSlot(out, iList); } - if ( hn === '' ) { break; } const pos = hn.indexOf('.'); - if ( pos === -1 ) { - if ( modifiers === 1 ) { break; } - hn = ''; - } else { - hn = hn.slice(pos + 1); - } + if ( pos === -1 ) { break; } + hn = hn.slice(pos + 1); + if ( hn === '*' ) { break; } + } + } + + retrieveGenerics(out) { + let iList = this.#hostnameToStringListMap.get(''); + if ( iList ) { this.#retrieveFromSlot(out, iList); } + iList = this.#hostnameToStringListMap.get('*'); + if ( iList ) { this.#retrieveFromSlot(out, iList); } + } + + retrieveSpecificsByRegex(out, hostname, url) { + let hn = hostname; + if ( hn === '' ) { return; } + const pathname = naivePathnameFromURL(url) ?? ''; + for (;;) { + this.#retrieveSpecificsByRegex(hn, out, hostname, pathname); + const pos = hn.indexOf('.'); + if ( pos === -1 ) { break; } + hn = hn.slice(pos + 1); } - if ( modifiers !== 0 && modifiers !== 3 ) { return; } - if ( this.regexToSlotIdMap.size === 0 ) { return; } - // TODO: consider using a combined regex to test once for whether - // iterating is worth it. - for ( const restr of this.regexToSlotIdMap.keys() ) { - let re = this.regexMap.get(restr); - if ( re === undefined ) { - this.regexMap.set(restr, (re = new RegExp(restr.slice(1,-1)))); + this.#retrieveSpecificsByRegex('', out, hostname, pathname); + } + + #retrieveSpecificsByRegex(hn, out, hostname, pathname) { + let iMatchList = this.#hostnameToMatcherListMap.get(hn) ?? 0; + while ( iMatchList !== 0 ) { + const iMatchSlot = this.#linkedLists[iMatchList+0]; + const matcher = this.#matcherSlots[iMatchSlot]; + if ( this.#matcherTest(matcher, hostname, pathname) ) { + this.#retrieveFromSlot(out, matcher.iList); } - if ( re.test(hostname) === false ) { continue; } - this.retrieveFromSlot(this.regexToSlotIdMap.get(restr), out); + iMatchList = this.#linkedLists[iMatchList+1]; + } + } + + #matcherTest(matcher, hn, pn) { + if ( matcher.isRegex === false ) { + return pn.startsWith(matcher.pn); + } + if ( this.#restrTest(matcher.hn, hn) === false ) { return false; } + if ( matcher.pn === undefined ) { return true; } + return this.#restrTest(matcher.pn, pn); + } + + #restrTest(restr, s) { + let re = this.#regexMap.get(restr); + if ( re === undefined ) { + this.#regexMap.set(restr, (re = new RegExp(restr))); } + return re.test(s); } - retrieveFromSlot(hnSlot, out) { - if ( hnSlot === undefined ) { return; } - const mask = out.length - 1; // out.length must be power of two + #retrieveFromSlot(out, iList) { + if ( iList === undefined ) { return; } do { - const strId = this.hostnameSlots[hnSlot+0]; - out[strId & mask].add(this.strSlots[strId >>> this.nBits]); - hnSlot = this.hostnameSlots[hnSlot+1]; - } while ( hnSlot !== 0 ); + const iStr = this.#linkedLists[iList+0]; + out.add(this.#strSlots[iStr]); + iList = this.#linkedLists[iList+1]; + } while ( iList !== 0 ); } toSelfie() { return { - version: this.version, - hostnameToSlotIdMap: this.hostnameToSlotIdMap, - regexToSlotIdMap: this.regexToSlotIdMap, - hostnameSlots: this.hostnameSlots, - strSlots: this.strSlots, + VERSION: StaticExtFilteringHostnameDB.VERSION, + hostnameToStringListMap: this.#hostnameToStringListMap, + matcherMap: this.#matcherMap, + hostnameToMatcherListMap: this.#hostnameToMatcherListMap, + strSlots: this.#strSlots, + matcherSlots: this.#matcherSlots, + linkedLists: this.#linkedLists, size: this.size }; } fromSelfie(selfie) { if ( typeof selfie !== 'object' || selfie === null ) { return; } - this.hostnameToSlotIdMap = selfie.hostnameToSlotIdMap; - // Regex-based lookup available in uBO 1.47.0 and above - if ( selfie.regexToSlotIdMap ) { - this.regexToSlotIdMap = selfie.regexToSlotIdMap; + if ( selfie.VERSION !== StaticExtFilteringHostnameDB.VERSION ) { + throw new TypeError('Bad selfie'); } - this.hostnameSlots = selfie.hostnameSlots; - this.strSlots = selfie.strSlots; + this.#hostnameToStringListMap = selfie.hostnameToStringListMap; + this.#matcherMap = selfie.matcherMap; + this.#hostnameToMatcherListMap = selfie.hostnameToMatcherListMap; + this.#strSlots = selfie.strSlots; + this.#matcherSlots = selfie.matcherSlots; + this.#linkedLists = selfie.linkedLists; this.size = selfie.size; } -}; - -/******************************************************************************/ - -export { - StaticExtFilteringHostnameDB, -}; +} /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/src/js/static-ext-filtering.js ublock-origin-1.67.0+dfsg/src/js/static-ext-filtering.js --- ublock-origin-1.62.0+dfsg/src/js/static-ext-filtering.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/static-ext-filtering.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,15 +19,11 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - import cosmeticFilteringEngine from './cosmetic-filtering.js'; import htmlFilteringEngine from './html-filtering.js'; import httpheaderFilteringEngine from './httpheader-filtering.js'; -import scriptletFilteringEngine from './scriptlet-filtering.js'; import logger from './logger.js'; +import scriptletFilteringEngine from './scriptlet-filtering.js'; /******************************************************************************* diff -Nru ublock-origin-1.62.0+dfsg/src/js/static-filtering-io.js ublock-origin-1.67.0+dfsg/src/js/static-filtering-io.js --- ublock-origin-1.62.0+dfsg/src/js/static-filtering-io.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/static-filtering-io.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ // https://www.reddit.com/r/uBlockOrigin/comments/oq6kt5/ubo_loads_generic_filter_instead_of_specific/ diff -Nru ublock-origin-1.62.0+dfsg/src/js/static-filtering-parser.js ublock-origin-1.67.0+dfsg/src/js/static-filtering-parser.js --- ublock-origin-1.62.0+dfsg/src/js/static-filtering-parser.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/static-filtering-parser.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,11 +19,9 @@ Home: https://github.com/gorhill/uBlock */ -/******************************************************************************/ - import * as cssTree from '../lib/csstree/css-tree.js'; import { ArglistParser } from './arglist-parser.js'; -import Regex from '../lib/regexanalyzer/regex.js'; +import { JSONPath } from './jsonpath.js'; /******************************************************************************* * @@ -185,6 +183,7 @@ export const NODE_TYPE_NET_OPTION_NAME_PING = iota++; export const NODE_TYPE_NET_OPTION_NAME_POPUNDER = iota++; export const NODE_TYPE_NET_OPTION_NAME_POPUP = iota++; +export const NODE_TYPE_NET_OPTION_NAME_REASON = iota++; export const NODE_TYPE_NET_OPTION_NAME_REDIRECT = iota++; export const NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE = iota++; export const NODE_TYPE_NET_OPTION_NAME_REMOVEPARAM = iota++; @@ -224,9 +223,11 @@ [ '1p', NODE_TYPE_NET_OPTION_NAME_1P ], /* synonym */ [ 'first-party', NODE_TYPE_NET_OPTION_NAME_1P ], [ 'strict1p', NODE_TYPE_NET_OPTION_NAME_STRICT1P ], + /* synonym */ [ 'strict-first-party', NODE_TYPE_NET_OPTION_NAME_STRICT1P ], [ '3p', NODE_TYPE_NET_OPTION_NAME_3P ], /* synonym */ [ 'third-party', NODE_TYPE_NET_OPTION_NAME_3P ], [ 'strict3p', NODE_TYPE_NET_OPTION_NAME_STRICT3P ], + /* synonym */ [ 'strict-third-party', NODE_TYPE_NET_OPTION_NAME_STRICT3P ], [ 'all', NODE_TYPE_NET_OPTION_NAME_ALL ], [ 'badfilter', NODE_TYPE_NET_OPTION_NAME_BADFILTER ], [ 'cname', NODE_TYPE_NET_OPTION_NAME_CNAME ], @@ -266,6 +267,7 @@ /* synonym */ [ 'beacon', NODE_TYPE_NET_OPTION_NAME_PING ], [ 'popunder', NODE_TYPE_NET_OPTION_NAME_POPUNDER ], [ 'popup', NODE_TYPE_NET_OPTION_NAME_POPUP ], + [ 'reason', NODE_TYPE_NET_OPTION_NAME_REASON ], [ 'redirect', NODE_TYPE_NET_OPTION_NAME_REDIRECT ], /* synonym */ [ 'rewrite', NODE_TYPE_NET_OPTION_NAME_REDIRECT ], [ 'redirect-rule', NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE ], @@ -335,6 +337,29 @@ /******************************************************************************/ +// Local constants + +const DOMAIN_CAN_USE_WILDCARD = 0b0000001; +const DOMAIN_CAN_USE_ENTITY = 0b0000010; +const DOMAIN_CAN_USE_SINGLE_WILDCARD = 0b0000100; +const DOMAIN_CAN_BE_NEGATED = 0b0001000; +const DOMAIN_CAN_BE_REGEX = 0b0010000; +const DOMAIN_CAN_BE_ANCESTOR = 0b0100000; +const DOMAIN_CAN_HAVE_PATH = 0b1000000; + +const DOMAIN_FROM_FROMTO_LIST = DOMAIN_CAN_USE_ENTITY | + DOMAIN_CAN_BE_NEGATED | + DOMAIN_CAN_BE_REGEX; +const DOMAIN_FROM_DENYALLOW_LIST = 0; +const DOMAIN_FROM_EXT_LIST = DOMAIN_CAN_USE_ENTITY | + DOMAIN_CAN_USE_SINGLE_WILDCARD | + DOMAIN_CAN_BE_NEGATED | + DOMAIN_CAN_BE_REGEX | + DOMAIN_CAN_BE_ANCESTOR | + DOMAIN_CAN_HAVE_PATH; + +/******************************************************************************/ + // Precomputed AST layouts for most common filters. const astTemplates = { @@ -587,11 +612,13 @@ 'ext_abp', 'adguard', 'adguard_app_android', + 'adguard_app_cli', 'adguard_app_ios', 'adguard_app_mac', 'adguard_app_windows', 'adguard_ext_android_cb', 'adguard_ext_chromium', + 'adguard_ext_chromium_mv3', 'adguard_ext_edge', 'adguard_ext_firefox', 'adguard_ext_opera', @@ -605,6 +632,9 @@ return pos >= 0 ? s.charCodeAt(pos) : -1; }; +const escapeForRegex = s => + s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + /******************************************************************************/ class AstWalker { @@ -762,7 +792,7 @@ this.selectorCompiler = new ExtSelectorCompiler(options); // Regexes this.reWhitespaceStart = /^\s+/; - this.reWhitespaceEnd = /\s+$/; + this.reWhitespaceEnd = /(?:^|\S)(\s+)$/; this.reCommentLine = /^(?:!|#\s|####|\[adblock)/i; this.reExtAnchor = /(#@?(?:\$\?|\$|%|\?)?#).{1,2}/; this.reInlineComment = /(?:\s+#).*?$/; @@ -782,7 +812,6 @@ this.reHostsRedirect = /(?:0\.0\.0\.0|broadcasthost|local|localhost(?:\.localdomain)?|ip6-\w+)(?:[^\w.-]|$)/; this.reNetOptionComma = /,(?:~?[13a-z-]+(?:=.*?)?|_+)(?:,|$)/; this.rePointlessLeftAnchor = /^\|\|?\*+/; - this.reIsTokenChar = /^[%0-9A-Za-z]/; this.rePointlessLeadingWildcards = /^(\*+)[^%0-9A-Za-z\u{a0}-\u{10FFFF}]/u; this.rePointlessTrailingSeparator = /\*(\^\**)$/; this.rePointlessTrailingWildcards = /(?:[^%0-9A-Za-z]|[%0-9A-Za-z]{7,})(\*+)$/; @@ -804,13 +833,19 @@ this.reHostnameLabel = /[^.]+/g; this.reResponseheaderPattern = /^\^responseheader\(.*\)$/; this.rePatternScriptletJsonArgs = /^\{.*\}$/; - this.reGoodRegexToken = /[^\x01%0-9A-Za-z][%0-9A-Za-z]{7,}|[^\x01%0-9A-Za-z][%0-9A-Za-z]{1,6}[^\x01%0-9A-Za-z]/; this.reBadCSP = /(?:^|[;,])\s*report-(?:to|uri)\b/i; this.reBadPP = /(?:^|[;,])\s*report-to\b/i; this.reNetOption = /^(~?)([134a-z_-]+)(=?)/; this.reNoopOption = /^_+$/; + this.reAdvancedDomainSyntax = /^([^>]+?)(>>)?(\/.*)?$/; this.netOptionValueParser = new ArglistParser(','); this.scriptletArgListParser = new ArglistParser(','); + this.domainRegexValueParser = new ArglistParser('/'); + this.reNetOptionTokens = new RegExp( + `^~?(${Array.from(netOptionTokenDescriptors.keys()) + .map(s => escapeForRegex(s)) + .join('|')})\\b` + ); } finish() { @@ -1165,7 +1200,7 @@ prev = this.linkRight(prev, next); patternBeg += 2; } - let anchorBeg = this.indexOfNetAnchor(parentStr, patternBeg); + let anchorBeg = this.indexOfNetAnchor(parentStr); if ( anchorBeg === -1 ) { return 0; } anchorBeg += parentBeg; if ( anchorBeg !== parentEnd ) { @@ -1210,7 +1245,7 @@ let modifierType = 0; let requestTypeCount = 0; let unredirectableTypeCount = 0; - let badfilter = false; + let isBadfilter = false; for ( let i = 0, n = this.nodeTypeRegisterPtr; i < n; i++ ) { const type = this.nodeTypeRegister[i]; const targetNode = this.nodeTypeLookupTable[type]; @@ -1234,7 +1269,7 @@ realBad = hasValue; break; case NODE_TYPE_NET_OPTION_NAME_BADFILTER: - badfilter = true; + isBadfilter = true; /* falls through */ case NODE_TYPE_NET_OPTION_NAME_NOOP: realBad = isNegated || hasValue; @@ -1243,7 +1278,6 @@ case NODE_TYPE_NET_OPTION_NAME_FONT: case NODE_TYPE_NET_OPTION_NAME_IMAGE: case NODE_TYPE_NET_OPTION_NAME_MEDIA: - case NODE_TYPE_NET_OPTION_NAME_OBJECT: case NODE_TYPE_NET_OPTION_NAME_OTHER: case NODE_TYPE_NET_OPTION_NAME_SCRIPT: case NODE_TYPE_NET_OPTION_NAME_XHR: @@ -1271,6 +1305,7 @@ break; case NODE_TYPE_NET_OPTION_NAME_DOC: case NODE_TYPE_NET_OPTION_NAME_FRAME: + case NODE_TYPE_NET_OPTION_NAME_OBJECT: realBad = hasValue; if ( realBad ) { break; } docTypeCount += 1; @@ -1315,7 +1350,7 @@ const value = this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_IPADDRESS); if ( /^\/.+\/$/.test(value) ) { try { void new RegExp(value); } - catch(_) { realBad = true; } + catch { realBad = true; } } break; } @@ -1345,6 +1380,9 @@ abstractTypeCount += 1; unredirectableTypeCount += 1; break; + case NODE_TYPE_NET_OPTION_NAME_REASON: + realBad = hasValue === false; + break; case NODE_TYPE_NET_OPTION_NAME_REDIRECT: case NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE: case NODE_TYPE_NET_OPTION_NAME_REPLACE: @@ -1385,9 +1423,6 @@ this.addFlags(AST_FLAG_HAS_ERROR); } } - const requiresTrustedSource = ( ) => - this.options.trustedSource !== true && - isException === false && badfilter === false; switch ( modifierType ) { case NODE_TYPE_NET_OPTION_NAME_CNAME: realBad = abstractTypeCount || behaviorTypeCount || requestTypeCount; @@ -1415,7 +1450,8 @@ case NODE_TYPE_NET_OPTION_NAME_REPLACE: { realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount; if ( realBad ) { break; } - if ( requiresTrustedSource() ) { + if ( isException || isBadfilter ) { break; } + if ( this.options.trustedSource !== true ) { this.astError = AST_ERROR_UNTRUSTED_SOURCE; realBad = true; break; @@ -1430,7 +1466,8 @@ case NODE_TYPE_NET_OPTION_NAME_URLSKIP: { realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount; if ( realBad ) { break; } - if ( requiresTrustedSource() ) { + if ( isException || isBadfilter ) { break; } + if ( this.options.trustedSource !== true ) { this.astError = AST_ERROR_UNTRUSTED_SOURCE; realBad = true; break; @@ -1445,13 +1482,14 @@ case NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM: { realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount; if ( realBad ) { break; } - if ( requiresTrustedSource() ) { + if ( isException || isBadfilter ) { break; } + if ( this.options.trustedSource !== true ) { this.astError = AST_ERROR_UNTRUSTED_SOURCE; realBad = true; break; } const value = this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM); - if ( value !== '' && parseReplaceValue(value) === undefined ) { + if ( value !== '' && parseReplaceByRegexValue(value) === undefined ) { this.astError = AST_ERROR_OPTION_BADVALUE; realBad = true; } @@ -1470,22 +1508,17 @@ } } - indexOfNetAnchor(s, start = 0) { + indexOfNetAnchor(s) { const end = s.length; - if ( end === start ) { return end; } + if ( end === 0 ) { return end; } let j = s.lastIndexOf('$'); if ( j === -1 ) { return end; } if ( (j+1) === end ) { return end; } for (;;) { const before = s.charAt(j-1); if ( before === '$' ) { return -1; } - const after = s.charAt(j+1); - if ( ')/|'.includes(after) === false ) { - if ( before === '' || '"\'\\`'.includes(before) === false ) { - return j; - } - } - if ( j === start ) { break; } + if ( this.reNetOptionTokens.test(s.slice(j+1)) ) { return j; } + if ( j === 0 ) { break; } j = s.lastIndexOf('$', j-1); if ( j === -1 ) { break; } } @@ -1615,12 +1648,6 @@ if ( normal !== pattern ) { this.setNodeTransform(next, normal); } - if ( this.interactive ) { - const tokenizable = utils.regex.toTokenizableStr(normal); - if ( this.reGoodRegexToken.test(tokenizable) === false ) { - this.addNodeFlags(next, NODE_FLAG_PATTERN_UNTOKENIZABLE); - } - } } else { this.astTypeFlavor = AST_TYPE_NETWORK_PATTERN_BAD; this.astError = AST_ERROR_REGEX; @@ -1839,7 +1866,7 @@ const hn = match[0].replace(this.reHostnameLabel, s => { if ( this.reHasUnicodeChar.test(s) === false ) { return s; } if ( s.charCodeAt(0) === 0x2D /* - */ ) { s = '*' + s; } - return this.normalizeHostnameValue(s, 0b0001) || s; + return this.normalizeHostnameValue(s, DOMAIN_CAN_USE_WILDCARD) || s; }); normal = hn + normal.slice(match.index + match[0].length); } @@ -1849,7 +1876,7 @@ normal = normal.replace(this.reUnicodeChars, s => encodeURIComponent(s).toLowerCase() ); - } catch (ex) { + } catch { return; } return normal; @@ -2018,11 +2045,11 @@ } switch ( nodeOptionType ) { case NODE_TYPE_NET_OPTION_NAME_DENYALLOW: - this.linkDown(next, this.parseDomainList(next, '|'), 0b00000); + this.linkDown(next, this.parseDomainList(next, '|'), DOMAIN_FROM_DENYALLOW_LIST); break; case NODE_TYPE_NET_OPTION_NAME_FROM: case NODE_TYPE_NET_OPTION_NAME_TO: - this.linkDown(next, this.parseDomainList(next, '|', 0b11010)); + this.linkDown(next, this.parseDomainList(next, '|', DOMAIN_FROM_FROMTO_LIST)); break; default: break; @@ -2054,7 +2081,7 @@ return this.getNodeTransform(valueNode); } - parseDomainList(parent, separator, mode = 0b00000) { + parseDomainList(parent, separator, mode = 0) { const parentBeg = this.nodes[parent+NODE_BEG_INDEX]; const parentEnd = this.nodes[parent+NODE_END_INDEX]; const containerNode = this.allocTypedNode( @@ -2080,11 +2107,20 @@ ); this.parseDomain(next, parseDetails); end = beg + parseDetails.len; + const badSeparator = end < listEnd && s.charCodeAt(end) !== separatorCode; + if ( badSeparator ) { + end = s.indexOf(separator, end); + if ( end === -1 ) { end = listEnd; } + } this.nodes[next+NODE_END_INDEX] = parentBeg + end; if ( end !== beg ) { domainNode = next; this.linkDown(domainNode, parseDetails.node); prev = this.linkRight(prev, domainNode); + if ( badSeparator ) { + this.addNodeFlags(domainNode, NODE_FLAG_ERROR); + this.addFlags(AST_FLAG_HAS_ERROR); + } } else { domainNode = 0; if ( separatorNode !== 0 ) { @@ -2128,29 +2164,29 @@ if ( not ) { this.addNodeFlags(parent, NODE_FLAG_IS_NEGATED); head = this.allocTypedNode(NODE_TYPE_OPTION_VALUE_NOT, beg, beg + 1); - if ( (parseDetails.mode & 0b1000) === 0 ) { + if ( (parseDetails.mode & DOMAIN_CAN_BE_NEGATED) === 0 ) { this.addNodeFlags(parent, NODE_FLAG_ERROR); } beg += 1; } const c0 = this.charCodeAt(beg); let end = beg; - let type = 0; + let isRegex = false; if ( c0 === 0x2F /* / */ ) { - end = this.indexOf('/', beg + 1, parentEnd); - if ( end !== -1 ) { end += 1; } - type = 1; + this.domainRegexValueParser.nextArg(this.raw, beg+1); + end = this.domainRegexValueParser.separatorEnd; + isRegex = true; } else if ( c0 === 0x5B /* [ */ && this.startsWith('[$domain=/', beg) ) { end = this.indexOf('/]', beg + 10, parentEnd); if ( end !== -1 ) { end += 2; } - type = 2; + isRegex = true; } else { end = this.indexOf(parseDetails.separator, end, parentEnd); } if ( end === -1 ) { end = parentEnd; } if ( beg !== end ) { next = this.allocTypedNode(NODE_TYPE_OPTION_VALUE_DOMAIN, beg, end); - const hn = this.normalizeDomainValue(next, type, parseDetails.mode); + const hn = this.normalizeDomainValue(next, isRegex, parseDetails.mode); if ( hn !== undefined ) { if ( hn !== '' ) { this.setNodeTransform(next, hn); @@ -2173,23 +2209,39 @@ parseDetails.len = end - parentBeg; } - // mode bits: - // 0b00001: can use wildcard at any position - // 0b00010: can use entity-based hostnames - // 0b00100: can use single wildcard - // 0b01000: can be negated - // 0b10000: can be a regex - normalizeDomainValue(node, type, modeBits) { - const s = this.getNodeString(node); - if ( type === 0 ) { - return this.normalizeHostnameValue(s, modeBits); - } - if ( (modeBits & 0b10000) === 0 ) { return ''; } - const regex = type === 1 ? s : `/${s.slice(10, -2)}/`; + normalizeDomainValue(node, isRegex, modeBits) { + const raw = this.getNodeString(node); + if ( isRegex ) { + if ( (modeBits & DOMAIN_CAN_BE_REGEX) === 0 ) { return ''; } + return this.normalizeDomainRegexValue(raw); + } + // Common: Assume plain hostname + const r1 = this.normalizeHostnameValue(raw, modeBits); + if ( r1 === undefined ) { return; } + if ( r1 !== '' ) { return r1; } + // Rare: Maybe advanced syntax is used + const match = this.reAdvancedDomainSyntax.exec(raw); + if ( match === null ) { return '' }; + const isAncestor = match[2] !== undefined; + if ( isAncestor && (modeBits & DOMAIN_CAN_BE_ANCESTOR) === 0 ) { return ''; } + const hasPath = match[3] !== undefined; + if ( hasPath && (modeBits & DOMAIN_CAN_HAVE_PATH) === 0 ) { return ''; } + if ( isAncestor && hasPath ) { return ''; } + const r2 = this.normalizeHostnameValue(match[1], modeBits); + if ( r2 === undefined ) { return; } + if ( r2 === '' ) { return ''; } + return `${r2}${match[2] ?? ''}${match[3] ?? ''}`; + } + + normalizeDomainRegexValue(before) { + const regex = before.startsWith('[$domain=/') + ? `${before.slice(9, -1)}` + : before; const source = this.normalizeRegexPattern(regex); if ( source === '' ) { return ''; } - if ( type === 1 && source === regex ) { return; } - return `/${source}/`; + const after = `/${source}/`; + if ( after === before ) { return; } + return after; } parseExt(parent, anchorBeg, anchorLen) { @@ -2207,7 +2259,8 @@ ); this.addFlags(AST_FLAG_HAS_OPTIONS); this.addNodeToRegister(NODE_TYPE_EXT_OPTIONS, next); - this.linkDown(next, this.parseDomainList(next, ',', 0b11110)); + const down = this.parseDomainList(next, ',', DOMAIN_FROM_EXT_LIST); + this.linkDown(next, down); prev = this.linkRight(prev, next); } next = this.allocTypedNode( @@ -2496,6 +2549,12 @@ return head; } + getResponseheaderName() { + if ( this.isResponseheaderFilter() === false ) { return ''; } + const root = this.getBranchFromType(NODE_TYPE_EXT_PATTERN_RESPONSEHEADER); + return this.getNodeString(root); + } + parseExtPatternHtml(parent) { const beg = this.nodes[parent+NODE_BEG_INDEX]; const end = this.nodes[parent+NODE_END_INDEX]; @@ -2737,7 +2796,7 @@ rightWhitespaceCount(s) { const match = this.reWhitespaceEnd.exec(s); - return match === null ? 0 : match[0].length; + return match === null ? 0 : match[1].length; } nextCommaInCommaSeparatedListString(s, start) { @@ -2794,17 +2853,11 @@ // Ultimately, let the browser API do the hostname normalization, after // making some other trivial checks. // - // mode bits: - // 0b00001: can use wildcard at any position - // 0b00010: can use entity-based hostnames - // 0b00100: can use single wildcard - // 0b01000: can be negated - // // returns: // undefined: no normalization needed, use original hostname // empty string: hostname is invalid // non-empty string: normalized hostname - normalizeHostnameValue(s, modeBits = 0b00000) { + normalizeHostnameValue(s, modeBits = 0) { if ( this.reHostnameAscii.test(s) ) { return; } if ( this.reBadHostnameChars.test(s) ) { return ''; } let hn = s; @@ -2812,13 +2865,13 @@ if ( hasWildcard ) { if ( modeBits === 0 ) { return ''; } if ( hn.length === 1 ) { - if ( (modeBits & 0b0100) === 0 ) { return ''; } + if ( (modeBits & DOMAIN_CAN_USE_SINGLE_WILDCARD) === 0 ) { return ''; } return; } - if ( (modeBits & 0b0010) !== 0 ) { + if ( (modeBits & DOMAIN_CAN_USE_ENTITY) !== 0 ) { if ( this.rePlainEntity.test(hn) ) { return; } if ( this.reIsEntity.test(hn) === false ) { return ''; } - } else if ( (modeBits & 0b0001) === 0 ) { + } else if ( (modeBits & DOMAIN_CAN_USE_WILDCARD) === 0 ) { return ''; } hn = hn.replace(/\*/g, '__asterisk__'); @@ -2827,7 +2880,7 @@ try { this.punycoder.hostname = hn; hn = this.punycoder.hostname; - } catch (_) { + } catch { return ''; } if ( hn === '_' || hn === '' ) { return ''; } @@ -2835,7 +2888,7 @@ hn = this.punycoder.hostname.replace(/__asterisk__/g, '*'); } if ( - (modeBits & 0b0001) === 0 && ( + (modeBits & DOMAIN_CAN_USE_WILDCARD) === 0 && ( hn.charCodeAt(0) === 0x2E /* . */ || exCharCodeAt(hn, -1) === 0x2E /* . */ ) @@ -2951,7 +3004,7 @@ try { out.re = new RegExp(match[1], match[2] || ''); } - catch(ex) { + catch { out.bad = true; } return out; @@ -2960,7 +3013,7 @@ if ( s.startsWith('|') ) { try { out.re = new RegExp('^' + s.slice(1), 'i'); - } catch(ex) { + } catch { out.bad = true; } return out; @@ -2979,28 +3032,47 @@ const out = { }; let pos = s.indexOf(':'); if ( pos === -1 ) { pos = s.length; } - out.name = s.slice(0, pos); + out.name = s.slice(0, pos).toLowerCase(); out.bad = out.name === ''; s = s.slice(pos + 1); out.not = s.charCodeAt(0) === 0x7E /* '~' */; if ( out.not ) { s = s.slice(1); } out.value = s; + if ( s === '' ) { return out; } const match = /^\/(.+)\/(i)?$/.exec(s); - if ( match !== null ) { - try { - out.re = new RegExp(match[1], match[2] || ''); - } - catch(ex) { - out.bad = true; - } + out.isRegex = match !== null; + if ( out.isRegex ) { + out.reStr = match[1]; + out.reFlags = match[2] || ''; + try { new RegExp(out.reStr, out.reFlags); } + catch { out.bad = true; } + return out; } + out.reFlags = 'i'; + if ( /[*?]/.test(s) === false ) { + out.reStr = escapeForRegex(s); + return out; + } + const reConstruct = /(?+~]\s*)(?:[A-Za-z_][\w-]*(?:[.#][A-Za-z_][\w-]*)*(?:\[[A-Za-z_][\w-]*(?:[*^$]?="[^"\]\\]+")?\])*|[.#][A-Za-z_][\w-]*(?:[.#][A-Za-z_][\w-]*)*(?:\[[A-Za-z_][\w-]*(?:[*^$]?="[^"\]\\]+")?\])*|\[[A-Za-z_][\w-]*(?:[*^$]?="[^"\]\\]+")?\](?:\[[A-Za-z_][\w-]*(?:[*^$]?="[^"\]\\]+")?\])*))*$/ this.reEatBackslashes = /\\([()])/g; - this.reEscapeRegex = /[.*+?^${}()|[\]\\]/g; // https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes this.knownPseudoClasses = new Set([ 'active', 'any-link', 'autofill', @@ -3979,7 +4077,7 @@ regexDetails = [ regexDetails, match[2] ]; } } else { - regexDetails = '^' + value.replace(this.reEscapeRegex, '\\$&') + '$'; + regexDetails = `^${escapeForRegex(value)}$`; } return { name, pseudo, value: regexDetails }; } @@ -4056,7 +4154,7 @@ try { const expr = doc.createExpression(r.s, null); expr.evaluate(doc, XPathResult.ANY_UNORDERED_NODE_TYPE); - } catch (e) { + } catch { return; } return r.s; @@ -4097,188 +4195,6 @@ export const utils = (( ) => { - // Depends on: - // https://github.com/foo123/RegexAnalyzer - const regexAnalyzer = Regex && Regex.Analyzer || null; - - class regex { - static firstCharCodeClass(s) { - return /^[\x01\x03%0-9A-Za-z]/.test(s) ? 1 : 0; - } - - static lastCharCodeClass(s) { - return /[\x01\x03%0-9A-Za-z]$/.test(s) ? 1 : 0; - } - - static tokenizableStrFromNode(node) { - switch ( node.type ) { - case 1: /* T_SEQUENCE, 'Sequence' */ { - let s = ''; - for ( let i = 0; i < node.val.length; i++ ) { - s += this.tokenizableStrFromNode(node.val[i]); - } - return s; - } - case 2: /* T_ALTERNATION, 'Alternation' */ - case 8: /* T_CHARGROUP, 'CharacterGroup' */ { - if ( node.flags.NegativeMatch ) { return '\x01'; } - let firstChar = 0; - let lastChar = 0; - for ( let i = 0; i < node.val.length; i++ ) { - const s = this.tokenizableStrFromNode(node.val[i]); - if ( firstChar === 0 && this.firstCharCodeClass(s) === 1 ) { - firstChar = 1; - } - if ( lastChar === 0 && this.lastCharCodeClass(s) === 1 ) { - lastChar = 1; - } - if ( firstChar === 1 && lastChar === 1 ) { break; } - } - return String.fromCharCode(firstChar, lastChar); - } - case 4: /* T_GROUP, 'Group' */ { - if ( - node.flags.NegativeLookAhead === 1 || - node.flags.NegativeLookBehind === 1 - ) { - return ''; - } - return this.tokenizableStrFromNode(node.val); - } - case 16: /* T_QUANTIFIER, 'Quantifier' */ { - if ( node.flags.max === 0 ) { return ''; } - const s = this.tokenizableStrFromNode(node.val); - const first = this.firstCharCodeClass(s); - const last = this.lastCharCodeClass(s); - if ( node.flags.min !== 0 ) { - return String.fromCharCode(first, last); - } - return String.fromCharCode(first+2, last+2); - } - case 64: /* T_HEXCHAR, 'HexChar' */ { - if ( - node.flags.Code === '01' || - node.flags.Code === '02' || - node.flags.Code === '03' - ) { - return '\x00'; - } - return node.flags.Char; - } - case 128: /* T_SPECIAL, 'Special' */ { - const flags = node.flags; - if ( - flags.EndCharGroup === 1 || // dangling `]` - flags.EndGroup === 1 || // dangling `)` - flags.EndRepeats === 1 // dangling `}` - ) { - throw new Error('Unmatched bracket'); - } - return flags.MatchEnd === 1 || - flags.MatchStart === 1 || - flags.MatchWordBoundary === 1 - ? '\x00' - : '\x01'; - } - case 256: /* T_CHARS, 'Characters' */ { - for ( let i = 0; i < node.val.length; i++ ) { - if ( this.firstCharCodeClass(node.val[i]) === 1 ) { - return '\x01'; - } - } - return '\x00'; - } - // Ranges are assumed to always involve token-related characters. - case 512: /* T_CHARRANGE, 'CharacterRange' */ { - return '\x01'; - } - case 1024: /* T_STRING, 'String' */ { - return node.val; - } - case 2048: /* T_COMMENT, 'Comment' */ { - return ''; - } - default: - break; - } - return '\x01'; - } - - static isValid(reStr) { - try { - void new RegExp(reStr); - if ( regexAnalyzer !== null ) { - void this.tokenizableStrFromNode( - regexAnalyzer(reStr, false).tree() - ); - } - } catch(ex) { - return false; - } - return true; - } - - static isRE2(reStr) { - if ( regexAnalyzer === null ) { return true; } - let tree; - try { - tree = regexAnalyzer(reStr, false).tree(); - } catch(ex) { - return; - } - const isRE2 = node => { - if ( node instanceof Object === false ) { return true; } - if ( node.flags instanceof Object ) { - if ( node.flags.LookAhead === 1 ) { return false; } - if ( node.flags.NegativeLookAhead === 1 ) { return false; } - if ( node.flags.LookBehind === 1 ) { return false; } - if ( node.flags.NegativeLookBehind === 1 ) { return false; } - } - if ( Array.isArray(node.val) ) { - for ( const entry of node.val ) { - if ( isRE2(entry) === false ) { return false; } - } - } - if ( node.val instanceof Object ) { - return isRE2(node.val); - } - return true; - }; - return isRE2(tree); - } - - static toTokenizableStr(reStr) { - if ( regexAnalyzer === null ) { return ''; } - let s = ''; - try { - s = this.tokenizableStrFromNode( - regexAnalyzer(reStr, false).tree() - ); - } catch(ex) { - } - // Process optional sequences - const reOptional = /[\x02\x03]+/; - for (;;) { - const match = reOptional.exec(s); - if ( match === null ) { break; } - const left = s.slice(0, match.index); - const middle = match[0]; - const right = s.slice(match.index + middle.length); - s = left; - s += this.firstCharCodeClass(right) === 1 || - this.firstCharCodeClass(middle) === 1 - ? '\x01' - : '\x00'; - s += this.lastCharCodeClass(left) === 1 || - this.lastCharCodeClass(middle) === 1 - ? '\x01' - : '\x00'; - s += right; - } - return s; - } - } - const preparserTokens = new Map([ [ 'ext_ublock', 'ublock' ], [ 'ext_ubol', 'ubol' ], @@ -4302,11 +4218,13 @@ // https://adguard.com/kb/general/ad-filtering/create-own-filters/#conditions-directive [ 'adguard', 'adguard' ], [ 'adguard_app_android', 'false' ], + [ 'adguard_app_cli', 'false' ], [ 'adguard_app_ios', 'false' ], [ 'adguard_app_mac', 'false' ], [ 'adguard_app_windows', 'false' ], [ 'adguard_ext_android_cb', 'false' ], [ 'adguard_ext_chromium', 'chromium' ], + [ 'adguard_ext_chromium_mv3', 'mv3' ], [ 'adguard_ext_edge', 'edge' ], [ 'adguard_ext_firefox', 'firefox' ], [ 'adguard_ext_opera', 'chromium' ], @@ -4316,7 +4234,7 @@ const toURL = url => { try { return new URL(url.trim()); - } catch (ex) { + } catch { } }; @@ -4496,7 +4414,6 @@ return { preparser, - regex, }; })(); diff -Nru ublock-origin-1.62.0+dfsg/src/js/static-net-filtering.js ublock-origin-1.67.0+dfsg/src/js/static-net-filtering.js --- ublock-origin-1.62.0+dfsg/src/js/static-net-filtering.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/static-net-filtering.js 2025-10-25 19:32:51.000000000 +0000 @@ -23,6 +23,7 @@ import { domainFromHostname, hostnameFromNetworkURL } from './uri-utils.js'; import { dropTask, queueTask } from './tasks.js'; +import { isRE2, toHeaderPattern, tokenizableStrFromRegex } from './regex-analyzer.js'; import BidiTrieContainer from './biditrie.js'; import { CompiledListReader } from './static-filtering-io.js'; @@ -299,9 +300,8 @@ }, lookup(name) { if ( this.parsed.size === 0 ) { - for ( let i = 0, n = this.headers.length; i < n; i++ ) { - const { name, value } = this.headers[i]; - this.parsed.set(name, value); + for ( const { name, value } of this.headers ) { + this.parsed.set(name.toLowerCase(), value); } } return this.parsed.get(name); @@ -410,6 +410,9 @@ } this.raw = raw; this.regex = logData.regex.join(''); + if ( logData.reason ) { + this.reason = logData.reason; + } } isUntokenized() { return this.tokenHash === NO_TOKEN_HASH; @@ -550,14 +553,6 @@ const bidiTrie = new BidiTrieContainer(bidiTrieMatchExtra); -const bidiTriePrime = ( ) => { - bidiTrie.reset(keyvalStore.getItem('SNFE.bidiTrie')); -}; - -const bidiTrieOptimize = (shrink = false) => { - keyvalStore.setItem('SNFE.bidiTrie', bidiTrie.optimize(shrink)); -}; - /******************************************************************************* Each filter class will register itself in the map. @@ -770,7 +765,7 @@ } static dnrFromCompiled(args, rule) { - rule.priority = (rule.priority || 0) + 30; + rule.__important = true; } static keyFromArgs() { @@ -804,7 +799,7 @@ if ( bidiTrie.startsWith( left, - bidiTrie.haystackLen, + bidiTrie.getHaystackLen(), filterData[idata+1], n ) === 0 @@ -881,7 +876,7 @@ if ( bidiTrie.startsWith( left, - bidiTrie.haystackLen, + bidiTrie.getHaystackLen(), filterData[idata+1], n ) === 0 @@ -904,7 +899,7 @@ if ( bidiTrie.startsWith( left, - bidiTrie.haystackLen, + bidiTrie.getHaystackLen(), filterData[idata+1], n ) === 0 @@ -1039,7 +1034,7 @@ lastBeg = len !== 0 ? haystackCodes.indexOf(0x3A) : -1; if ( lastBeg !== -1 ) { if ( - lastBeg >= bidiTrie.haystackLen || + lastBeg >= bidiTrie.getHaystackLen() || haystackCodes[lastBeg+1] !== 0x2F || haystackCodes[lastBeg+2] !== 0x2F ) { @@ -1236,7 +1231,6 @@ ); } if ( refs.$re.test($requestURLRaw) === false ) { return false; } - $patternMatchLeft = $requestURLRaw.search(refs.$re); return true; } @@ -1262,7 +1256,7 @@ if ( rule.condition === undefined ) { rule.condition = {}; } - if ( sfp.utils.regex.isRE2(args[1]) === false ) { + if ( isRE2(args[1]) === false ) { dnrAddRuleError(rule, `regexFilter is not RE2-compatible: ${args[1]}`); } rule.condition.regexFilter = args[1]; @@ -2936,18 +2930,26 @@ if ( refs.$parsed === null ) { refs.$parsed = sfp.parseHeaderValue(refs.headerOpt); } - const { bad, name, not, re, value } = refs.$parsed; + const { bad, name, not, value } = refs.$parsed; if ( bad ) { return false; } const headerValue = $httpHeaders.lookup(name); if ( headerValue === undefined ) { return false; } if ( value === '' ) { return true; } - return re === undefined - ? (headerValue === value) !== not - : re.test(headerValue) !== not; + let { re } = refs.$parsed; + if ( re === undefined ) { + re = new RegExp(refs.$parsed.reStr, refs.$parsed.reFlags); + refs.$parsed.re = re; + } + return re.test(headerValue) !== not; } static compile(details) { - return [ FilterOnHeaders.fid, details.optionValues.get('header') ]; + const parsed = sfp.parseHeaderValue(details.optionValues.get('header')); + let normalized = parsed.name; + if ( parsed.value !== '' ) { + normalized += `:${parsed.value}`; + } + return [ FilterOnHeaders.fid, normalized ]; } static fromCompiled(args) { @@ -2961,6 +2963,27 @@ } static dnrFromCompiled(args, rule) { + rule.condition ||= {}; + const parsed = sfp.parseHeaderValue(args[1]); + if ( parsed.bad !== true ) { + const value = parsed.isRegex + ? toHeaderPattern(parsed.reStr) + : parsed.value; + if ( value !== undefined ) { + const prop = parsed.not + ? 'excludedResponseHeaders' + : 'responseHeaders'; + rule.condition[prop] ||= []; + const details = { + header: parsed.name, + }; + if ( value !== '' ) { + details.values = [ value ]; + } + rule.condition[prop].push(details); + return; + } + } dnrAddRuleError(rule, `header="${args[1]}" not supported`); } @@ -3082,6 +3105,40 @@ registerFilterClass(FilterIPAddress); /******************************************************************************/ + +class FilterMessage { + static match() { + return true; + } + + static compile(details) { + return [ + FilterMessage.fid, + encodeURIComponent(details.optionValues.get('reason')), + ]; + } + + static fromCompiled(args) { + const msg = args[1]; + return filterDataAlloc(args[0], bidiTrie.storeString(msg), msg.length); + } + + static keyFromArgs(args) { + return `${args[1]}`; + } + + static logData(idata, details) { + const reason = decodeURIComponent( + bidiTrie.extractString(filterData[idata+1], filterData[idata+2]) + ); + details.reason = reason; + details.options.push(`reason=${reason}`); + } +} + +registerFilterClass(FilterMessage); + +/******************************************************************************/ /******************************************************************************/ // https://github.com/gorhill/uBlock/issues/2630 @@ -3112,7 +3169,7 @@ this._hasQuery = 0; // https://www.reddit.com/r/uBlockOrigin/comments/dzw57l/ // Remember: 1 token needs two slots - this._tokens = new Uint32Array(2064); + this._tokens = new Uint32Array(bidiTrie.haystack.length + 16); this.knownTokens = new Uint8Array(65536); this.resetKnownTokens(); @@ -3142,9 +3199,9 @@ } // Tokenize on demand. - getTokens(encodeInto) { + getTokens() { if ( this._tokenized ) { return this._tokens; } - let i = this._tokenize(encodeInto); + let i = this._tokenize(); this._tokens[i+0] = ANY_TOKEN_HASH; this._tokens[i+1] = 0; i += 2; @@ -3201,22 +3258,17 @@ // https://github.com/chrisaljoudi/uBlock/issues/1118 // We limit to a maximum number of tokens. - _tokenize(encodeInto) { + _tokenize() { const tokens = this._tokens; - let url = this._urlOut; - let l = url.length; + const url = this._urlOut; + const l = bidiTrie.setHaystackLen(url.length); if ( l === 0 ) { return 0; } - if ( l > 2048 ) { - url = url.slice(0, 2048); - l = 2048; - } - encodeInto.haystackLen = l; let j = 0; let hasq = -1; mainLoop: { const knownTokens = this.knownTokens; const vtc = this._validTokenChars; - const charCodes = encodeInto.haystack; + const charCodes = bidiTrie.haystack; let i = 0, n = 0, ti = 0, th = 0; for (;;) { for (;;) { @@ -3263,7 +3315,7 @@ if ( other !== undefined ) { return Object.assign(this, other); } - this.reToken = /[%0-9A-Za-z]+/g; + this.reTokens = /[%0-9A-Za-z]+/g; this.optionValues = new Map(); this.tokenIdToNormalizedType = new Map([ [ sfp.NODE_TYPE_NET_OPTION_NAME_CNAME, bitFromType('cname') ], @@ -3453,7 +3505,7 @@ try { const re = new RegExp(s); return re.source; - } catch (ex) { + } catch { } return ''; } @@ -3576,6 +3628,10 @@ } this.optionUnitBits |= MODIFY_BIT; break; + case sfp.NODE_TYPE_NET_OPTION_NAME_REASON: + this.optionValues.set('reason', parser.getNetOptionValue(id)); + this.optionUnitBits |= MESSAGE_BIT; + break; case sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECT: { const actualId = this.action === ALLOW_REALM ? sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE @@ -3684,6 +3740,7 @@ case sfp.NODE_TYPE_NET_OPTION_NAME_IPADDRESS: case sfp.NODE_TYPE_NET_OPTION_NAME_METHOD: case sfp.NODE_TYPE_NET_OPTION_NAME_PERMISSIONS: + case sfp.NODE_TYPE_NET_OPTION_NAME_REASON: case sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECT: case sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE: case sfp.NODE_TYPE_NET_OPTION_NAME_REMOVEPARAM: @@ -3814,11 +3871,11 @@ // Note: a one-char token is better than a documented bad token. extractTokenFromPattern(pattern) { - this.reToken.lastIndex = 0; + this.reTokens.lastIndex = 0; let bestMatch = null; let bestBadness = 0x7FFFFFFF; for (;;) { - const match = this.reToken.exec(pattern); + const match = this.reTokens.exec(pattern); if ( match === null ) { break; } const token = match[0]; const badness = token.length > 1 ? this.badTokens.get(token) || 0 : 1; @@ -3828,7 +3885,7 @@ if ( c === 0x2A /* '*' */ ) { continue; } } if ( token.length < MAX_TOKEN_LENGTH ) { - const lastIndex = this.reToken.lastIndex; + const lastIndex = this.reTokens.lastIndex; if ( lastIndex < pattern.length ) { const c = pattern.charCodeAt(lastIndex); if ( c === 0x2A /* '*' */ ) { continue; } @@ -3852,18 +3909,18 @@ // Mind `\b` directives: `/\bads\b/` should result in token being `ads`, // not `bads`. extractTokenFromRegex(pattern) { - pattern = sfp.utils.regex.toTokenizableStr(pattern); - this.reToken.lastIndex = 0; + pattern = tokenizableStrFromRegex(pattern); + this.reTokens.lastIndex = 0; let bestToken; let bestBadness = 0x7FFFFFFF; for (;;) { - const matches = this.reToken.exec(pattern); + const matches = this.reTokens.exec(pattern); if ( matches === null ) { break; } const { 0: token, index } = matches; if ( index === 0 || pattern.charAt(index - 1) === '\x01' ) { continue; } - const { lastIndex } = this.reToken; + const { lastIndex } = this.reTokens; if ( token.length < MAX_TOKEN_LENGTH && ( lastIndex === pattern.length || @@ -4064,6 +4121,11 @@ this.action |= HEADERS_REALM; } + // Message + if ( (this.optionUnitBits & MESSAGE_BIT) !== 0 ) { + units.push(FilterMessage.compile(this)); + } + // Important // // IMPORTANT: must always appear at the end of the sequence, so as to @@ -4158,16 +4220,17 @@ } // These are to quickly test whether a filter is composite -const FROM_BIT = 0b0000000001; -const TO_BIT = 0b0000000010; -const DENYALLOW_BIT = 0b0000000100; -const HEADER_BIT = 0b0000001000; -const STRICT_PARTY_BIT = 0b0000010000; -const MODIFY_BIT = 0b0000100000; -const NOT_TYPE_BIT = 0b0001000000; -const IMPORTANT_BIT = 0b0010000000; -const METHOD_BIT = 0b0100000000; -const IPADDRESS_BIT = 0b1000000000; +const FROM_BIT = 0b00000000001; +const TO_BIT = 0b00000000010; +const DENYALLOW_BIT = 0b00000000100; +const HEADER_BIT = 0b00000001000; +const STRICT_PARTY_BIT = 0b00000010000; +const MODIFY_BIT = 0b00000100000; +const NOT_TYPE_BIT = 0b00001000000; +const IMPORTANT_BIT = 0b00010000000; +const METHOD_BIT = 0b00100000000; +const IPADDRESS_BIT = 0b01000000000; +const MESSAGE_BIT = 0b10000000000 FilterCompiler.prototype.FILTER_OK = 0; FilterCompiler.prototype.FILTER_INVALID = 1; @@ -4201,7 +4264,6 @@ destHNTrieContainer.reset( keyvalStore.getItem('SNFE.destHNTrieContainer.trieDetails') ); - bidiTriePrime(); }; /******************************************************************************/ @@ -4341,7 +4403,7 @@ if ( op === 'begin' ) { Object.assign(context, { good: new Set(), - bad: new Set(), + bad: new Set(context.bad), invalid: new Set(), filterCount: 0, acceptedFilterCount: 0, @@ -4464,12 +4526,15 @@ const realms = new Map([ [ BLOCK_REALM, { type: 'block', priority: 10 } ], [ ALLOW_REALM, { type: 'allow', priority: 30 } ], + [ BLOCK_REALM | IMPORTANT_REALM, { type: 'block', priority: 10 } ], [ REDIRECT_REALM, { type: 'redirect', priority: 11 } ], [ REMOVEPARAM_REALM, { type: 'removeparam', priority: 0 } ], [ CSP_REALM, { type: 'csp', priority: 0 } ], [ PERMISSIONS_REALM, { type: 'permissions', priority: 0 } ], [ URLTRANSFORM_REALM, { type: 'uritransform', priority: 0 } ], [ HEADERS_REALM, { type: 'block', priority: 10 } ], + [ HEADERS_REALM | ALLOW_REALM, { type: 'allow', priority: 30 } ], + [ HEADERS_REALM | IMPORTANT_REALM, { type: 'allow', priority: 10 } ], [ URLSKIP_REALM, { type: 'urlskip', priority: 0 } ], ]); const partyness = new Map([ @@ -4493,6 +4558,7 @@ 'other', ]); const ruleset = []; + const seen = new Set(); for ( const [ realmBits, realmDetails ] of realms ) { for ( const [ partyBits, partyName ] of partyness ) { for ( const typeName in typeNameToTypeValue ) { @@ -4516,15 +4582,32 @@ rule.condition = rule.condition || {}; rule.condition.resourceTypes = [ typeName ]; } + const hash = JSON.stringify(rule); + if ( seen.has(hash) ) { continue; } + seen.add(hash); ruleset.push(rule); } } } } } + seen.clear(); + + // Adjust `important` priority + // Mind: + // - https://github.com/uBlockOrigin/uAssets/issues/29451#issuecomment-3150181993 + for ( const rule of ruleset ) { + if ( rule.__important !== true ) { continue; } + if ( rule.priority === undefined ) { + if ( rule.__modifierType !== 'removeparam' ) { continue; } + rule.priority ||= 0; + } + rule.priority += 30; + } // Collect generichide filters const generichideExclusions = []; + const generichideInclusions = []; { const bucket = buckets.get(ALLOW_REALM | typeNameToTypeValue['generichide']); if ( bucket ) { @@ -4536,6 +4619,26 @@ } else if ( rule.condition.requestDomains ) { generichideExclusions.push(...rule.condition.requestDomains); } + if ( rule.condition.excludedInitiatorDomains ) { + generichideInclusions.push(...rule.condition.excludedInitiatorDomains); + } else if ( rule.condition.excludedRequestDomains ) { + generichideInclusions.push(...rule.condition.excludedRequestDomains); + } + } + } + } + } + { + const bucket = buckets.get(BLOCKIMPORTANT_REALM | typeNameToTypeValue['generichide']); + if ( bucket ) { + for ( const rules of bucket.values() ) { + for ( const rule of rules ) { + if ( rule.condition === undefined ) { continue; } + if ( rule.condition.initiatorDomains ) { + generichideInclusions.push(...rule.condition.initiatorDomains); + } else if ( rule.condition.requestDomains ) { + generichideInclusions.push(...rule.condition.requestDomains); + } } } } @@ -4579,6 +4682,7 @@ // Patch modifier filters for ( const rule of ruleset ) { if ( rule.__modifierType === undefined ) { continue; } + let patchDomainOption = false; switch ( rule.__modifierType ) { case 'csp': rule.action.type = 'modifyHeaders'; @@ -4601,13 +4705,14 @@ if ( rule.__modifierAction === ALLOW_REALM ) { dnrAddRuleError(rule, `Unsupported permissions exception: ${rule.__modifierValue}`); } + patchDomainOption = true; break; case 'redirect-rule': { let token = rule.__modifierValue; if ( token !== '' ) { const match = /:(\d+)$/.exec(token); if ( match !== null ) { - rule.priority += Math.min(rule.priority + parseInt(match[1], 10), 9); + rule.priority += Math.min(parseInt(match[1], 10), 8); token = token.slice(0, match.index); } } @@ -4677,7 +4782,19 @@ break; } case 'uritransform': { - dnrAddRuleError(rule, `Incompatible with DNR: uritransform=${rule.__modifierValue}`); + const parsed = sfp.parseReplaceByRegexValue(rule.__modifierValue); + if ( parsed.re !== undefined ) { + dnrAddRuleError(rule, `Incompatible with DNR: uritransform=${rule.__modifierValue}`); + break; + } + if ( rule.condition.regexFilter === undefined ) { + dnrAddRuleError(rule, `Incompatible with DNR (need regexFilter): uritransform=${rule.__modifierValue}`); + break; + } + rule.action.type = 'redirect'; + rule.action.redirect = { + regexSubstitution: parsed.replacement.replace(/\$(\d+)/g, '\\$1') + }; break; } case 'urlskip': { @@ -4703,6 +4820,21 @@ dnrAddRuleError(rule, `Unsupported modifier ${rule.__modifierType}`); break; } + + // Some modifiers only work on document resources + // Related issue: https://github.com/uBlockOrigin/uBOL-home/issues/156 + if ( patchDomainOption ) { + const domains = rule.condition.initiatorDomains; + if ( Array.isArray(domains) && domains.length !== 0 ) { + rule.condition.requestDomains ||= []; + rule.condition.requestDomains.push(...domains); + } + const notDomains = rule.condition.excludedInitiatorDomains; + if ( Array.isArray(notDomains) && notDomains.length !== 0 ) { + rule.condition.excludedRequestDomains ||= []; + rule.condition.excludedRequestDomains.push(...notDomains); + } + } } return { @@ -4711,6 +4843,7 @@ acceptedFilterCount: context.acceptedFilterCount, rejectedFilterCount: context.rejectedFilterCount, generichideExclusions: Array.from(new Set(generichideExclusions)), + generichideInclusions: Array.from(new Set(generichideInclusions)), }; }; @@ -4793,7 +4926,6 @@ 'SNFE.destHNTrieContainer.trieDetails', destHNTrieContainer.optimize() ); - bidiTrieOptimize(); filterDataShrink(); }; @@ -4801,7 +4933,7 @@ StaticNetFilteringEngine.prototype.toSelfie = function() { this.optimize(0); - bidiTrieOptimize(true); + bidiTrie.optimize(); keyvalStore.setItem('SNFE.origHNTrieContainer.trieDetails', origHNTrieContainer.optimize() ); @@ -4944,7 +5076,7 @@ results, }; - const tokenHashes = urlTokenizer.getTokens(bidiTrie); + const tokenHashes = urlTokenizer.getTokens(); let i = 0; let th = 0, iunit = 0; for (;;) { @@ -5035,8 +5167,7 @@ toRemove.delete(key); } } - } - else if ( toAdd.size !== 0 ) { + } else if ( toAdd.size !== 0 ) { toAdd.clear(); if ( toRemove.size !== 1 ) { const entry = toRemove.get(''); @@ -5134,7 +5265,7 @@ } // Pattern-based filters else { - const tokenHashes = urlTokenizer.getTokens(bidiTrie); + const tokenHashes = urlTokenizer.getTokens(); let i = 0; for (;;) { tokenHash = tokenHashes[i]; @@ -5309,6 +5440,7 @@ $requestMethodBit = fctxt.method || 0; $requestTypeValue = (typeBits & TYPE_REALM) >>> TYPE_REALM_OFFSET; $requestAddress = fctxt.getIPAddress(); + $isBlockImportant = false; $httpHeaders.init(headers); let r = 0; @@ -5378,7 +5510,7 @@ /******************************************************************************/ -StaticNetFilteringEngine.prototype.transformRequest = function(fctxt, out = []) { +StaticNetFilteringEngine.prototype.transformURL = function(fctxt, out = []) { const directives = this.matchAndFetchModifiers(fctxt, 'uritransform'); if ( directives === undefined ) { return; } const redirectURL = new URL(fctxt.url); @@ -5388,21 +5520,25 @@ continue; } if ( directive.cache === null ) { - directive.cache = sfp.parseReplaceValue(directive.value); + directive.cache = sfp.parseReplaceByRegexValue(directive.value); } const cache = directive.cache; if ( cache === undefined ) { continue; } - const before = `${redirectURL.pathname}${redirectURL.search}${redirectURL.hash}`; - if ( cache.re.test(before) !== true ) { continue; } - const after = before.replace(cache.re, cache.replacement); + let { re } = cache; + const before = redirectURL.href; + if ( re === undefined ) { + const logdata = directive.logData(); + if ( logdata === undefined ) { continue; } + try { re = new RegExp(logdata.regex, cache.flags); } + catch { continue; } + } + if ( re.test(before) !== true ) { continue; } + const after = before.replace(re, cache.replacement); + try { void new URL(after); } catch { continue; } if ( after === before ) { continue; } - const hashPos = after.indexOf('#'); - redirectURL.hash = hashPos !== -1 ? after.slice(hashPos) : ''; - const afterMinusHash = hashPos !== -1 ? after.slice(0, hashPos) : after; - const searchPos = afterMinusHash.indexOf('?'); - redirectURL.search = searchPos !== -1 ? afterMinusHash.slice(searchPos) : ''; - redirectURL.pathname = searchPos !== -1 ? after.slice(0, searchPos) : after; + redirectURL.href = after; out.push(directive); + break; } if ( out.length === 0 ) { return; } if ( redirectURL.href !== fctxt.url ) { @@ -5452,7 +5588,7 @@ if ( qpos === -1 ) { return; } let hpos = url.indexOf('#', qpos + 1); if ( hpos === -1 ) { hpos = url.length; } - const params = new Map(); + const params = []; const query = url.slice(qpos + 1, hpos); for ( let i = 0; i < query.length; ) { let pos = query.indexOf('&', i); @@ -5461,14 +5597,14 @@ i = pos + 1; pos = kv.indexOf('='); if ( pos !== -1 ) { - params.set(kv.slice(0, pos), kv.slice(pos + 1)); + params.push(kv.slice(0, pos), kv.slice(pos + 1)); } else { - params.set(kv, ''); + params.push(kv, ''); } } - const inParamCount = params.size; + const beforeParamCount = params.length; for ( const directive of directives ) { - if ( params.size === 0 ) { break; } + if ( params.length === 0 ) { break; } const isException = (directive.bits & ALLOW_REALM) !== 0; if ( isException && directive.value === '' ) { out.push(directive); @@ -5477,35 +5613,29 @@ const { all, bad, name, not, re } = parseQueryPruneValue(directive); if ( bad ) { continue; } if ( all ) { - if ( isException === false ) { params.clear(); } + if ( isException === false ) { params.length = 0; } out.push(directive); break; } - if ( name !== undefined ) { - const value = params.get(name); - if ( not === false ) { - if ( value !== undefined ) { - if ( isException === false ) { params.delete(name); } - out.push(directive); - } - continue; - } - if ( value !== undefined ) { params.delete(name); } - if ( params.size !== 0 ) { - if ( isException === false ) { params.clear(); } - out.push(directive); - } - if ( value !== undefined ) { params.set(name, value); } - continue; - } - if ( re === undefined ) { continue; } let filtered = false; - for ( const [ key, raw ] of params ) { - let value = raw; - try { value = decodeURIComponent(value); } - catch(ex) { } - if ( re.test(`${key}=${value}`) === not ) { continue; } - if ( isException === false ) { params.delete(key); } + let matched = false; + let i = params.length; + while ( i > 0 ) { + i -= 2; + if ( name !== undefined ) { + matched = params[i] === name; + } else if ( re !== undefined ) { + const key = params[i+0]; + const raw = params[i+1]; + let value = raw; + try { value = decodeURIComponent(value); } + catch { } + matched = re.test(`${key}=${value}`); + } + if ( matched === not ) { continue; } + if ( isException === false ) { + params.splice(i, 2); + } filtered = true; } if ( filtered ) { @@ -5513,12 +5643,16 @@ } } if ( out.length === 0 ) { return; } - if ( params.size !== inParamCount ) { + if ( params.length !== beforeParamCount ) { fctxt.redirectURL = url.slice(0, qpos); - if ( params.size !== 0 ) { - fctxt.redirectURL += '?' + Array.from(params).map(a => - a[1] === '' ? `${a[0]}=` : `${a[0]}=${a[1]}` - ).join('&'); + if ( params.length !== 0 ) { + const queryParts = []; + for ( let i = 0; i < params.length; i += 2 ) { + const key = params[i+0]; + const val = params[i+1]; + queryParts.push(val !== '' ? `${key}=${val}` : key); + } + fctxt.redirectURL += '?' + queryParts.join('&'); } if ( hpos !== url.length ) { fctxt.redirectURL += url.slice(hpos); @@ -5602,7 +5736,7 @@ out.push('not blocked'); } if ( r !== 1 ) { - const entries = this.transformRequest(fctxt); + const entries = this.transformURL(fctxt); if ( entries ) { for ( const entry of entries ) { out.push(`modified: ${entry.logData().raw}`); diff -Nru ublock-origin-1.62.0+dfsg/src/js/storage.js ublock-origin-1.67.0+dfsg/src/js/storage.js --- ublock-origin-1.62.0+dfsg/src/js/storage.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/storage.js 2025-10-25 19:32:51.000000000 +0000 @@ -42,18 +42,12 @@ import punycode from '../lib/punycode.js'; import { redirectEngine } from './redirect-engine.js'; import staticExtFilteringEngine from './static-ext-filtering.js'; -import staticFilteringReverseLookup from './reverselookup.js'; +import { staticFilteringReverseLookup } from './reverselookup.js'; import staticNetFilteringEngine from './static-net-filtering.js'; import µb from './background.js'; /******************************************************************************/ -// https://eslint.org/docs/latest/rules/no-prototype-builtins -const hasOwnProperty = (o, p) => - Object.prototype.hasOwnProperty.call(o, p); - -/******************************************************************************/ - µb.getBytesInUse = async function() { const promises = []; let bytesInUse; @@ -186,7 +180,7 @@ for ( const entry of adminSettings ) { if ( entry.length < 1 ) { continue; } const name = entry[0]; - if ( hasOwnProperty(usDefault, name) === false ) { continue; } + if ( Object.hasOwn(usDefault, name) === false ) { continue; } const value = entry.length < 2 ? usDefault[name] : this.settingValueFromString(usDefault, name, entry[1]); @@ -215,8 +209,8 @@ const toRemove = []; for ( const key in this.userSettings ) { - if ( hasOwnProperty(this.userSettings, key) === false ) { continue; } - if ( hasOwnProperty(toSave, key) ) { continue; } + if ( Object.hasOwn(this.userSettings, key) === false ) { continue; } + if ( Object.hasOwn(toSave, key) ) { continue; } toRemove.push(key); } if ( toRemove.length !== 0 ) { @@ -253,7 +247,7 @@ for ( const entry of advancedSettings ) { if ( entry.length < 1 ) { continue; } const name = entry[0]; - if ( hasOwnProperty(hsDefault, name) === false ) { continue; } + if ( Object.hasOwn(hsDefault, name) === false ) { continue; } const value = entry.length < 2 ? hsDefault[name] : this.hiddenSettingValueFromString(name, entry[1]); @@ -287,8 +281,8 @@ } for ( const key in hsDefault ) { - if ( hasOwnProperty(hsDefault, key) === false ) { continue; } - if ( hasOwnProperty(hsAdmin, name) ) { continue; } + if ( Object.hasOwn(hsDefault, key) === false ) { continue; } + if ( Object.hasOwn(hsAdmin, name) ) { continue; } if ( typeof hs[key] !== typeof hsDefault[key] ) { continue; } this.hiddenSettings[key] = hs[key]; } @@ -334,8 +328,8 @@ const matches = /^\s*(\S+)\s+(.+)$/.exec(line); if ( matches === null || matches.length !== 3 ) { continue; } const name = matches[1]; - if ( hasOwnProperty(out, name) === false ) { continue; } - if ( hasOwnProperty(this.hiddenSettingsAdmin, name) ) { continue; } + if ( Object.hasOwn(out, name) === false ) { continue; } + if ( Object.hasOwn(this.hiddenSettingsAdmin, name) ) { continue; } const value = this.hiddenSettingValueFromString(name, matches[2]); if ( value !== undefined ) { out[name] = value; @@ -347,7 +341,7 @@ µb.hiddenSettingValueFromString = function(name, value) { if ( typeof name !== 'string' || typeof value !== 'string' ) { return; } const hsDefault = this.hiddenSettingsDefault; - if ( hasOwnProperty(hsDefault, name) === false ) { return; } + if ( Object.hasOwn(hsDefault, name) === false ) { return; } let r; switch ( typeof hsDefault[name] ) { case 'boolean': @@ -435,7 +429,7 @@ try { const url = new URL(prefix); if ( url.hostname.length > 0 ) { return url.href; } - } catch(_) { + } catch { } }).filter(prefix => prefix !== undefined); } @@ -688,7 +682,7 @@ µb.autoSelectRegionalFilterLists = function(lists) { const selectedListKeys = [ this.userFiltersPath ]; for ( const key in lists ) { - if ( hasOwnProperty(lists, key) === false ) { continue; } + if ( Object.hasOwn(lists, key) === false ) { continue; } const list = lists[key]; if ( list.content !== 'filters' ) { continue; } if ( list.off !== true ) { @@ -941,7 +935,7 @@ let acceptedCount = snfe.acceptedCount + sxfe.acceptedCount; let discardedCount = snfe.discardedCount + sxfe.discardedCount; µb.applyCompiledFilters(compiled, assetKey === µb.userFiltersPath); - if ( hasOwnProperty(µb.availableFilterLists, assetKey) ) { + if ( Object.hasOwn(µb.availableFilterLists, assetKey) ) { const entry = µb.availableFilterLists[assetKey]; entry.entryCount = snfe.acceptedCount + sxfe.acceptedCount - acceptedCount; @@ -977,7 +971,7 @@ // content. const toLoad = []; for ( const assetKey in lists ) { - if ( hasOwnProperty(lists, assetKey) === false ) { continue; } + if ( Object.hasOwn(lists, assetKey) === false ) { continue; } if ( lists[assetKey].off ) { continue; } toLoad.push( µb.getCompiledFilterList(assetKey).then(details => { @@ -1428,8 +1422,8 @@ const µbus = this.userSettings; const adminus = data.userSettings; for ( const name in µbus ) { - if ( hasOwnProperty(µbus, name) === false ) { continue; } - if ( hasOwnProperty(adminus, name) === false ) { continue; } + if ( Object.hasOwn(µbus, name) === false ) { continue; } + if ( Object.hasOwn(adminus, name) === false ) { continue; } bin[name] = adminus[name]; binNotEmpty = true; } @@ -1600,7 +1594,7 @@ if ( topic === 'before-asset-updated' ) { if ( details.type === 'filters' ) { if ( - hasOwnProperty(this.availableFilterLists, details.assetKey) === false || + Object.hasOwn(this.availableFilterLists, details.assetKey) === false || this.selectedFilterLists.indexOf(details.assetKey) === -1 || this.badLists.get(details.assetKey) ) { @@ -1615,7 +1609,7 @@ // Skip selfie-related content. if ( details.assetKey.startsWith('selfie/') ) { return; } const cached = typeof details.content === 'string' && details.content !== ''; - if ( hasOwnProperty(this.availableFilterLists, details.assetKey) ) { + if ( Object.hasOwn(this.availableFilterLists, details.assetKey) ) { if ( cached ) { if ( this.selectedFilterLists.indexOf(details.assetKey) !== -1 ) { this.extractFilterListMetadata( diff -Nru ublock-origin-1.62.0+dfsg/src/js/support.js ublock-origin-1.67.0+dfsg/src/js/support.js --- ublock-origin-1.62.0+dfsg/src/js/support.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/support.js 2025-10-25 19:32:51.000000000 +0000 @@ -21,10 +21,8 @@ /* global CodeMirror, uBlockDashboard */ -'use strict'; - -import { onBroadcast } from './broadcast.js'; import { dom, qs$ } from './dom.js'; +import { onBroadcast } from './broadcast.js'; /******************************************************************************/ @@ -220,7 +218,7 @@ hostname: parsedURL.hostname.replace(/^(m|mobile|www)\./, ''), popupPanel: JSON.parse(url.searchParams.get('popupPanel')), }; - } catch(ex) { + } catch { } return null; })(); diff -Nru ublock-origin-1.62.0+dfsg/src/js/tab.js ublock-origin-1.67.0+dfsg/src/js/tab.js --- ublock-origin-1.62.0+dfsg/src/js/tab.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/tab.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,18 +19,11 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - -import contextMenu from './contextmenu.js'; -import logger from './logger.js'; -import scriptletFilteringEngine from './scriptlet-filtering.js'; -import staticNetFilteringEngine from './static-net-filtering.js'; -import µb from './background.js'; -import webext from './webext.js'; -import { PageStore } from './pagestore.js'; -import { i18n$ } from './i18n.js'; +import { + domainFromHostname, + hostnameFromURI, + originFromURI, +} from './uri-utils.js'; import { sessionFirewall, @@ -38,11 +31,14 @@ sessionURLFiltering, } from './filtering-engines.js'; -import { - domainFromHostname, - hostnameFromURI, - originFromURI, -} from './uri-utils.js'; +import { PageStore } from './pagestore.js'; +import contextMenu from './contextmenu.js'; +import { i18n$ } from './i18n.js'; +import logger from './logger.js'; +import scriptletFilteringEngine from './scriptlet-filtering.js'; +import staticNetFilteringEngine from './static-net-filtering.js'; +import webext from './webext.js'; +import µb from './background.js'; /******************************************************************************/ /******************************************************************************/ @@ -65,7 +61,7 @@ } try { tabURLNormalizer.href = tabURL; - } catch(ex) { + } catch { return tabURL; } const protocol = tabURLNormalizer.protocol.slice(0, -1); @@ -574,18 +570,15 @@ frameId: sourceFrameId, }), ]); - } - catch (reason) { - return; - } - if ( - Array.isArray(openerDetails) === false || - openerDetails.length !== 2 || - openerDetails[1] === null || - openerDetails[1].url === 'about:newtab' - ) { + } catch { return; } + if ( Array.isArray(openerDetails) === false ) { return; } + if ( openerDetails.length !== 2 ) { return; } + if ( openerDetails[1] === null ) { return; } + if ( openerDetails[1].url === 'about:newtab' ) { return; } + // https://github.com/uBlockOrigin/uBlock-issues/issues/2227 + if ( openerDetails[1].url.startsWith('chrome:') ) { return; } popupCandidates.set( tabId, new PopupCandidate(createDetails, openerDetails) @@ -933,6 +926,7 @@ if ( pageStore === null ) { return; } pageStore.setFrameURL(details); if ( pageStore.getNetFilteringSwitch() ) { + details.ancestors = pageStore.getFrameAncestorDetails(frameId); scriptletFilteringEngine.injectNow(details); } } diff -Nru ublock-origin-1.62.0+dfsg/src/js/tasks.js ublock-origin-1.67.0+dfsg/src/js/tasks.js --- ublock-origin-1.62.0+dfsg/src/js/tasks.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/tasks.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,12 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -/* globals requestIdleCallback, cancelIdleCallback */ - -'use strict'; - -/******************************************************************************/ - export function queueTask(func, timeout = 5000) { if ( typeof requestIdleCallback === 'undefined' ) { return setTimeout(func, 1); diff -Nru ublock-origin-1.62.0+dfsg/src/js/text-encode.js ublock-origin-1.67.0+dfsg/src/js/text-encode.js --- ublock-origin-1.62.0+dfsg/src/js/text-encode.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/text-encode.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,10 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - import µb from './background.js'; /******************************************************************************/ @@ -67,64 +63,64 @@ // http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1250.TXT const cp1250_range0 = new Uint8Array([ - /* 0x0100 */ 0x00, 0x00, 0xC3, 0xE3, 0xA5, 0xB9, 0xC6, 0xE6, - /* 0x0108 */ 0x00, 0x00, 0x00, 0x00, 0xC8, 0xE8, 0xCF, 0xEF, - /* 0x0110 */ 0xD0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0118 */ 0xCA, 0xEA, 0xCC, 0xEC, 0x00, 0x00, 0x00, 0x00, - /* 0x0120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0130 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0138 */ 0x00, 0xC5, 0xE5, 0x00, 0x00, 0xBC, 0xBE, 0x00, - /* 0x0140 */ 0x00, 0xA3, 0xB3, 0xD1, 0xF1, 0x00, 0x00, 0xD2, - /* 0x0148 */ 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0150 */ 0xD5, 0xF5, 0x00, 0x00, 0xC0, 0xE0, 0x00, 0x00, - /* 0x0158 */ 0xD8, 0xF8, 0x8C, 0x9C, 0x00, 0x00, 0xAA, 0xBA, - /* 0x0160 */ 0x8A, 0x9A, 0xDE, 0xFE, 0x8D, 0x9D, 0x00, 0x00, - /* 0x0168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xF9, - /* 0x0170 */ 0xDB, 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0178 */ 0x00, 0x8F, 0x9F, 0xAF, 0xBF, 0x8E, 0x9E, 0x00 + /* 0x0100 */ 0x00, 0x00, 0xC3, 0xE3, 0xA5, 0xB9, 0xC6, 0xE6, + /* 0x0108 */ 0x00, 0x00, 0x00, 0x00, 0xC8, 0xE8, 0xCF, 0xEF, + /* 0x0110 */ 0xD0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0118 */ 0xCA, 0xEA, 0xCC, 0xEC, 0x00, 0x00, 0x00, 0x00, + /* 0x0120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0130 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0138 */ 0x00, 0xC5, 0xE5, 0x00, 0x00, 0xBC, 0xBE, 0x00, + /* 0x0140 */ 0x00, 0xA3, 0xB3, 0xD1, 0xF1, 0x00, 0x00, 0xD2, + /* 0x0148 */ 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0150 */ 0xD5, 0xF5, 0x00, 0x00, 0xC0, 0xE0, 0x00, 0x00, + /* 0x0158 */ 0xD8, 0xF8, 0x8C, 0x9C, 0x00, 0x00, 0xAA, 0xBA, + /* 0x0160 */ 0x8A, 0x9A, 0xDE, 0xFE, 0x8D, 0x9D, 0x00, 0x00, + /* 0x0168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xF9, + /* 0x0170 */ 0xDB, 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0178 */ 0x00, 0x8F, 0x9F, 0xAF, 0xBF, 0x8E, 0x9E, 0x00 ]); // http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1251.TXT const cp1251_range0 = new Uint8Array([ - /* 0x0400 */ 0x00, 0xA8, 0x80, 0x81, 0xAA, 0xBD, 0xB2, 0xAF, - /* 0x0408 */ 0xA3, 0x8A, 0x8C, 0x8E, 0x8D, 0x00, 0xA1, 0x8F, - /* 0x0410 */ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, - /* 0x0418 */ 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, - /* 0x0420 */ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, - /* 0x0428 */ 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, - /* 0x0430 */ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, - /* 0x0438 */ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, - /* 0x0440 */ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, - /* 0x0448 */ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, - /* 0x0450 */ 0x00, 0xB8, 0x90, 0x83, 0xBA, 0xBE, 0xB3, 0xBF, - /* 0x0458 */ 0xBC, 0x9A, 0x9C, 0x9E, 0x9D, 0x00, 0xA2, 0x9F, - /* 0x0460 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0468 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0470 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0478 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0480 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0488 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0490 */ 0xA5, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + /* 0x0400 */ 0x00, 0xA8, 0x80, 0x81, 0xAA, 0xBD, 0xB2, 0xAF, + /* 0x0408 */ 0xA3, 0x8A, 0x8C, 0x8E, 0x8D, 0x00, 0xA1, 0x8F, + /* 0x0410 */ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + /* 0x0418 */ 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + /* 0x0420 */ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, + /* 0x0428 */ 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + /* 0x0430 */ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + /* 0x0438 */ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + /* 0x0440 */ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + /* 0x0448 */ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, + /* 0x0450 */ 0x00, 0xB8, 0x90, 0x83, 0xBA, 0xBE, 0xB3, 0xBF, + /* 0x0458 */ 0xBC, 0x9A, 0x9C, 0x9E, 0x9D, 0x00, 0xA2, 0x9F, + /* 0x0460 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0468 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0470 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0478 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0480 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0488 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0490 */ 0xA5, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]); // https://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT const cp1252_range0 = new Uint8Array([ - /* 0x0150 */ 0x00, 0x00, 0x8C, 0x9C, 0x00, 0x00, 0x00, 0x00, - /* 0x0158 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0160 */ 0x8A, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0170 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0178 */ 0x9F, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x9E, 0x00 + /* 0x0150 */ 0x00, 0x00, 0x8C, 0x9C, 0x00, 0x00, 0x00, 0x00, + /* 0x0158 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0160 */ 0x8A, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0170 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0178 */ 0x9F, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x9E, 0x00 ]); const cp125x_range0 = new Uint8Array([ - /* 0x2010 */ 0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, - /* 0x2018 */ 0x91, 0x92, 0x82, 0x00, 0x93, 0x94, 0x84, 0x00, - /* 0x2020 */ 0x86, 0x87, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00, - /* 0x2028 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x2030 */ 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x2038 */ 0x00, 0x8B, 0x9B, 0x00, 0x00, 0x00, 0x00, 0x00 + /* 0x2010 */ 0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, + /* 0x2018 */ 0x91, 0x92, 0x82, 0x00, 0x93, 0x94, 0x84, 0x00, + /* 0x2020 */ 0x86, 0x87, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00, + /* 0x2028 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x2030 */ 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x2038 */ 0x00, 0x8B, 0x9B, 0x00, 0x00, 0x00, 0x00, 0x00 ]); const encoders = { @@ -255,7 +251,7 @@ return { encode: function(charset, buf) { - return encoders.hasOwnProperty(charset) ? + return Object.hasOwn(encoders, charset) ? encoders[charset](buf) : buf; }, diff -Nru ublock-origin-1.62.0+dfsg/src/js/text-utils.js ublock-origin-1.67.0+dfsg/src/js/text-utils.js --- ublock-origin-1.62.0+dfsg/src/js/text-utils.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/text-utils.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ // https://bugs.chromium.org/p/v8/issues/detail?id=2869 diff -Nru ublock-origin-1.62.0+dfsg/src/js/theme.js ublock-origin-1.67.0+dfsg/src/js/theme.js --- ublock-origin-1.62.0+dfsg/src/js/theme.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/theme.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - function getActualTheme(nominalTheme) { let theme = nominalTheme || 'light'; if ( nominalTheme === 'auto' ) { @@ -51,7 +49,7 @@ if ( propagate === false ) { break; } if ( w === w.parent ) { break; } w = w.parent; - try { void w.document; } catch(ex) { return; } + try { void w.document; } catch { return; } } } @@ -110,7 +108,7 @@ if ( propagate === false ) { break; } if ( w === w.parent ) { break; } w = w.parent; - try { void w.document; } catch(ex) { break; } + try { void w.document; } catch { break; } } } diff -Nru ublock-origin-1.62.0+dfsg/src/js/traffic.js ublock-origin-1.67.0+dfsg/src/js/traffic.js --- ublock-origin-1.62.0+dfsg/src/js/traffic.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/traffic.js 2025-10-25 19:32:51.000000000 +0000 @@ -39,20 +39,8 @@ /******************************************************************************/ -// Platform-specific behavior. - -// https://github.com/uBlockOrigin/uBlock-issues/issues/42 -// https://bugzilla.mozilla.org/show_bug.cgi?id=1376932 -// Add proper version number detection once issue is fixed in Firefox. -let dontCacheResponseHeaders = - vAPI.webextFlavor.soup.has('firefox'); - -// The real actual webextFlavor value may not be set in stone, so listen -// for possible future changes. -window.addEventListener('webextFlavor', function() { - dontCacheResponseHeaders = - vAPI.webextFlavor.soup.has('firefox'); -}, { once: true }); +// For platform-specific behavior. +const isGecko = vAPI.webextFlavor.isGecko; /******************************************************************************/ @@ -64,7 +52,7 @@ // Intercept and filter web requests. -const onBeforeRequest = function(details) { +function onBeforeRequest(details) { const fctxt = µb.filteringContext.fromWebrequestDetails(details); // Special handling for root document. @@ -129,7 +117,7 @@ /******************************************************************************/ -const onBeforeRootFrameRequest = function(fctxt) { +function onBeforeRootFrameRequest(fctxt) { const requestURL = fctxt.url; // Special handling for root document. @@ -221,24 +209,34 @@ // Blocked + let reason = logData.reason; + // Find out the URL navigated to should the document not be strict-blocked pageStore.skipMainDocument(fctxt, false); - const query = encodeURIComponent(JSON.stringify({ + if ( reason === undefined && Array.isArray(fctxt.filter) ) { + const filter = fctxt.filter.find(a => a.reason !== undefined); + reason = filter?.reason; + } + + const query = { url: requestURL, dn: fctxt.getDomain() || requestHostname, fs: logData.raw, hn: requestHostname, to: fctxt.redirectURL || '', - })); + }; + if ( reason ) { + query.reason = reason; + } vAPI.tabs.replace( fctxt.tabId, - vAPI.getURL('document-blocked.html?details=') + query + `${vAPI.getURL('document-blocked.html?details=')}${encodeURIComponent(JSON.stringify(query))}` ); return { cancel: true }; -}; +} /******************************************************************************/ @@ -268,7 +266,7 @@ // | 2 | rg | rg | rs | rs | // --------+--------+--------+--------+--------+--------+ -const shouldStrictBlock = function(fctxt, loggerEnabled) { +function shouldStrictBlock(fctxt, loggerEnabled) { const snfe = staticNetFilteringEngine; // Explicit filtering: `document` option @@ -328,7 +326,7 @@ // | 2 | - | - | - | x | // --------+--------+--------+--------+--------+--------+ return { result: rs, logData: lds }; -}; +} /******************************************************************************/ @@ -338,7 +336,7 @@ // Do not strict-block if the filter pattern does not contain at least one // token character. -const validateStrictBlock = function(fctxt, logData) { +function validateStrictBlock(fctxt, logData) { if ( typeof logData.regex !== 'string' ) { return false; } if ( typeof logData.raw === 'string' && /\w/.test(logData.raw) === false ) { return false; @@ -360,13 +358,13 @@ const end = match.index + match[0].length - hnpos - hnlen; return end === 0 || end === 1 || end === 2 && url.charCodeAt(hnpos + hnlen) === 0x2E /* '.' */; -}; +} /******************************************************************************/ // Intercept and filter behind-the-scene requests. -const onBeforeBehindTheSceneRequest = function(fctxt) { +function onBeforeBehindTheSceneRequest(fctxt) { const pageStore = µb.pageStoreFromTabId(fctxt.tabId); if ( pageStore === null ) { return; } @@ -426,7 +424,7 @@ if ( result === 1 ) { return { cancel: true }; } -}; +} // https://github.com/uBlockOrigin/uBlock-issues/issues/1204 // Report the tabless network requests to all page stores matching the @@ -481,7 +479,7 @@ // - HTML filtering (requires ability to modify response body) // - CSP injection -const onHeadersReceived = function(details) { +function onHeadersReceived(details) { const fctxt = µb.filteringContext.fromWebrequestDetails(details); const isRootDoc = fctxt.itype === fctxt.MAIN_FRAME; @@ -493,6 +491,12 @@ } if ( pageStore.getNetFilteringSwitch(fctxt) === false ) { return; } + // To enforce strict-blocking with ipaddress option + if ( isRootDoc && fctxt.ipaddress ) { + const r = onBeforeRootFrameRequest(fctxt); + if ( r ) { return ( r ); } + } + if ( (fctxt.itype & foilLargeMediaElement.TYPE_BITS) !== 0 ) { const result = foilLargeMediaElement(details, fctxt, pageStore); if ( result !== undefined ) { return result; } @@ -579,7 +583,7 @@ // https://github.com/uBlockOrigin/uBlock-issues/issues/229 // Use `no-cache` instead of `no-cache, no-store, must-revalidate`, this // allows Firefox's offline mode to work as expected. - if ( modifiedHeaders && dontCacheResponseHeaders ) { + if ( modifiedHeaders && isGecko ) { const cacheControl = µb.hiddenSettings.cacheControlForFirefox1376932; if ( cacheControl !== 'unset' ) { let i = headerIndexFromName('cache-control', responseHeaders); @@ -595,7 +599,7 @@ if ( modifiedHeaders ) { return { responseHeaders }; } -}; +} const reMediaContentTypes = /^(?:audio|image|video)\/|(?:\/ogg)$/; @@ -625,19 +629,62 @@ continue; } const { refs } = directive; + if ( refs.$cache !== null ) { + const { jsonp } = refs.$cache; + if ( jsonp && jsonp.apply === undefined ) { + refs.$cache = null; + } + } if ( refs.$cache === null ) { refs.$cache = sfp.parseReplaceValue(refs.value); } const cache = refs.$cache; if ( cache === undefined ) { continue; } - cache.re.lastIndex = 0; - if ( cache.re.test(session.getString()) !== true ) { continue; } - cache.re.lastIndex = 0; - session.setString(session.getString().replace( - cache.re, - cache.replacement - )); - applied.push(directive); + switch ( cache.type ) { + case 'json': { + const json = session.getString(); + let obj; + try { obj = JSON.parse(json); } catch { break; } + const objAfter = cache.jsonp.apply(obj); + if ( objAfter === undefined ) { break; } + session.setString(cache.jsonp.toJSON(objAfter)); + applied.push(directive); + break; + } + case 'jsonl': { + const linesBefore = session.getString().split(/\n+/); + const linesAfter = []; + for ( const lineBefore of linesBefore ) { + let obj; + try { obj = JSON.parse(lineBefore); } catch { } + if ( typeof obj !== 'object' || obj === null ) { + linesAfter.push(lineBefore); + continue; + } + const objAfter = cache.jsonp.apply(obj); + if ( objAfter === undefined ) { + linesAfter.push(lineBefore); + continue; + } + linesAfter.push(cache.jsonp.toJSON(objAfter)); + } + session.setString(linesAfter.join('\n')); + break; + } + case 'text': { + cache.re.lastIndex = 0; + if ( cache.re.test(session.getString()) !== true ) { break; } + cache.re.lastIndex = 0; + session.setString(session.getString().replace( + cache.re, + cache.replacement + )); + applied.push(directive); + break; + } + default: + break; + } } if ( applied.length === 0 ) { return; } if ( logger.enabled !== true ) { return; } @@ -958,7 +1005,7 @@ /******************************************************************************/ -const injectCSP = function(fctxt, pageStore, responseHeaders) { +function injectCSP(fctxt, pageStore, responseHeaders) { const cspSubsets = []; const requestType = fctxt.type; @@ -1085,11 +1132,11 @@ }); return true; -}; +} /******************************************************************************/ -const injectPP = function(fctxt, pageStore, responseHeaders) { +function injectPP(fctxt, pageStore, responseHeaders) { const permissions = []; const directives = staticNetFilteringEngine.matchAndFetchModifiers(fctxt, 'permissions'); if ( directives !== undefined ) { @@ -1115,7 +1162,7 @@ }); return true; -}; +} /******************************************************************************/ @@ -1126,7 +1173,7 @@ // cache. This works only when the webext API supports the `fromCache` // property (Firefox). -const foilLargeMediaElement = function(details, fctxt, pageStore) { +function foilLargeMediaElement(details, fctxt, pageStore) { if ( details.fromCache === true ) { return; } onDemandHeaders.setHeaders(details.responseHeaders); @@ -1142,7 +1189,7 @@ } return { cancel: true }; -}; +} foilLargeMediaElement.TYPE_BITS = fc.IMAGE | fc.MEDIA | fc.XMLHTTPREQUEST; @@ -1227,6 +1274,23 @@ /******************************************************************************/ +function onResponseStarted(details) { + if ( details.tabId === -1 ) { return; } + const pageStore = µb.pageStoreFromTabId(details.tabId); + if ( pageStore === null ) { return; } + if ( pageStore.getNetFilteringSwitch() === false ) { return; } + // To enforce strict-blocking with ipaddress option + if ( isGecko === false && details.type === 'main_frame' ) { + const fctxt = µb.filteringContext.fromWebrequestDetails(details); + const r = onBeforeRootFrameRequest(fctxt); + if ( r?.cancel ) { return; } + } + details.ancestors = pageStore.getFrameAncestorDetails(details.frameId); + scriptletFilteringEngine.injectNow(details); +} + +/******************************************************************************/ + // https://github.com/uBlockOrigin/uBlock-issues/issues/2350 // Added scriptlet injection attempt at onResponseStarted time as per // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1029 and @@ -1243,26 +1307,13 @@ return ( ) => { vAPI.net.setSuspendableListener(onBeforeRequest); - vAPI.net.addListener( - 'onHeadersReceived', - onHeadersReceived, - { urls: [ 'http://*/*', 'https://*/*' ] }, - [ 'blocking', 'responseHeaders' ] - ); - vAPI.net.addListener( - 'onResponseStarted', - details => { - if ( details.tabId === -1 ) { return; } - const pageStore = µb.pageStoreFromTabId(details.tabId); - if ( pageStore === null ) { return; } - if ( pageStore.getNetFilteringSwitch() === false ) { return; } - scriptletFilteringEngine.injectNow(details); - }, - { - types: [ 'main_frame', 'sub_frame' ], - urls: [ 'http://*/*', 'https://*/*' ] - } - ); + vAPI.net.addListener('onHeadersReceived', onHeadersReceived, { + urls: [ 'http://*/*', 'https://*/*' ] + }, [ 'blocking', 'responseHeaders' ]); + vAPI.net.addListener('onResponseStarted', onResponseStarted, { + types: [ 'main_frame', 'sub_frame' ], + urls: [ 'http://*/*', 'https://*/*' ] + }); vAPI.defer.once({ sec: µb.hiddenSettings.toolbarWarningTimeout }).then(( ) => { if ( vAPI.net.hasUnprocessedRequest() === false ) { return; } vAPI.net.removeUnprocessedRequest(); diff -Nru ublock-origin-1.62.0+dfsg/src/js/ublock.js ublock-origin-1.67.0+dfsg/src/js/ublock.js --- ublock-origin-1.62.0+dfsg/src/js/ublock.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/ublock.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,27 +19,28 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - -import io from './assets.js'; -import µb from './background.js'; -import { broadcast, filteringBehaviorChanged, onBroadcast } from './broadcast.js'; -import contextMenu from './contextmenu.js'; -import cosmeticFilteringEngine from './cosmetic-filtering.js'; -import { redirectEngine } from './redirect-engine.js'; -import { hostnameFromURI } from './uri-utils.js'; +import { + broadcast, + filteringBehaviorChanged, + onBroadcast, +} from './broadcast.js'; import { permanentFirewall, - sessionFirewall, permanentSwitches, - sessionSwitches, permanentURLFiltering, + sessionFirewall, + sessionSwitches, sessionURLFiltering, } from './filtering-engines.js'; +import contextMenu from './contextmenu.js'; +import cosmeticFilteringEngine from './cosmetic-filtering.js'; +import { hostnameFromURI } from './uri-utils.js'; +import io from './assets.js'; +import { redirectEngine } from './redirect-engine.js'; +import µb from './background.js'; + /******************************************************************************/ /******************************************************************************/ @@ -47,7 +48,7 @@ // Be more flexible with whitelist syntax // Any special regexp char will be escaped -const whitelistDirectiveEscape = /[-\/\\^$+?.()|[\]{}]/g; +const whitelistDirectiveEscape = /[-/\\^$+?.()|[\]{}]/g; // All `*` will be expanded into `.*` const whitelistDirectiveEscapeAsterisk = /\*/g; @@ -254,7 +255,7 @@ try { const re = new RegExp(directive.slice(1, -1)); directiveToRegexpMap.set(directive, re); - } catch(ex) { + } catch { key = '#'; directive = '# ' + line; } @@ -294,8 +295,8 @@ }; // https://github.com/gorhill/uBlock/issues/3717 -µb.reWhitelistBadHostname = /[^a-z0-9.\-_\[\]:]/; -µb.reWhitelistHostnameExtractor = /([a-z0-9.\-_\[\]]+)(?::[\d*]+)?\/(?:[^\x00-\x20\/]|$)[^\x00-\x20]*$/; +µb.reWhitelistBadHostname = /[^a-z0-9.\-_[\]:]/; +µb.reWhitelistHostnameExtractor = /([a-z0-9.\-_[\]]+)(?::[\d*]+)?\/(?:[^\x00-\x20/]|$)[^\x00-\x20]*$/; /******************************************************************************/ @@ -332,7 +333,7 @@ } // Change -- but only if the user setting actually exists. - const mustSave = us.hasOwnProperty(name) && value !== us[name]; + const mustSave = Object.hasOwn(us, name) && value !== us[name]; if ( mustSave ) { us[name] = value; } @@ -369,7 +370,7 @@ case 'noLargeMedia': case 'noRemoteFonts': case 'noScripting': - case 'noCSPReports': + case 'noCSPReports': { let switchName; switch ( name ) { case 'noCosmeticFiltering': @@ -392,6 +393,7 @@ this.saveHostnameSwitches(); } break; + } case 'prefetchingDisabled': if ( this.privacySettingsSupported ) { vAPI.browserSettings.set({ 'prefetching': !value }); @@ -588,39 +590,40 @@ // Take per-switch action if needed switch ( details.name ) { - case 'no-scripting': - this.updateToolbarIcon(details.tabId, 0b100); - break; - case 'no-cosmetic-filtering': { - const scriptlet = newState ? 'cosmetic-off' : 'cosmetic-on'; - vAPI.tabs.executeScript(details.tabId, { - file: `/js/scriptlets/${scriptlet}.js`, - allFrames: true, - }); - break; + case 'no-scripting': + this.updateToolbarIcon(details.tabId, 0b100); + break; + case 'no-cosmetic-filtering': { + const scriptlet = newState ? 'cosmetic-off' : 'cosmetic-on'; + vAPI.tabs.executeScript(details.tabId, { + file: `/js/scriptlets/${scriptlet}.js`, + allFrames: true, + }); + break; + } + case 'no-large-media': { + const pageStore = this.pageStoreFromTabId(details.tabId); + if ( pageStore !== null ) { + pageStore.temporarilyAllowLargeMediaElements(!newState); } - case 'no-large-media': - const pageStore = this.pageStoreFromTabId(details.tabId); - if ( pageStore !== null ) { - pageStore.temporarilyAllowLargeMediaElements(!newState); - } - break; - default: - break; + break; + } + default: + break; } // Flush caches if needed if ( newState ) { switch ( details.name ) { - case 'no-scripting': - case 'no-remote-fonts': - filteringBehaviorChanged({ - direction: details.state ? 1 : 0, - hostname: details.hostname, - }); - break; - default: - break; + case 'no-scripting': + case 'no-remote-fonts': + filteringBehaviorChanged({ + direction: details.state ? 1 : 0, + hostname: details.hostname, + }); + break; + default: + break; } } @@ -691,7 +694,7 @@ try { const url = new URL(pageURL); return JSON.parse(url.searchParams.get('details')).url; - } catch(ex) { + } catch { } } return pageURL; diff -Nru ublock-origin-1.62.0+dfsg/src/js/uri-utils.js ublock-origin-1.67.0+dfsg/src/js/uri-utils.js --- ublock-origin-1.62.0+dfsg/src/js/uri-utils.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/uri-utils.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,10 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - import publicSuffixList from '../lib/publicsuffixlist/publicsuffixlist.js'; import punycode from '../lib/punycode.js'; @@ -34,7 +30,7 @@ const reHostnameFromCommonURL = /^https:\/\/[0-9a-z._-]+[0-9a-z]\//; const reAuthorityFromURI = - /^(?:[^:\/?#]+:)?(\/\/[^\/?#]+)/; + /^(?:[^:/?#]+:)?(\/\/[^/?#]+)/; const reHostFromNakedAuthority = /^[0-9a-z._-]+[0-9a-z]$/i; const reHostFromAuthority = @@ -44,7 +40,7 @@ const reMustNormalizeHostname = /[^0-9a-z._-]/; const reOriginFromURI = - /^[^:\/?#]+:\/\/[^\/?#]+/; + /^[^:/?#]+:\/\/[^/?#]+/; const reHostnameFromNetworkURL = /^(?:http|ws|ftp)s?:\/\/([0-9a-z_][0-9a-z._-]*[0-9a-z])(?::\d+)?\//; const reIPAddressNaive = @@ -54,7 +50,7 @@ // For performance purpose, as simple tests as possible const reIPv4VeryCoarse = /\.\d+$/; -const reHostnameVeryCoarse = /[g-z_\-]/; +const reHostnameVeryCoarse = /[g-z_-]/; /******************************************************************************/ @@ -74,6 +70,15 @@ return pos !== -1 ? domain.slice(0, pos) + '.*' : ''; } +function entityFromHostname(hostname, domain) { + if ( domain === undefined ) { + domain = domainFromHostname(hostname); + } + const entity = entityFromDomain(domain); + if ( entity === '' ) { return ''; } + return `${hostname.slice(0, -domain.length)}${entity}` +} + function hostnameFromURI(uri) { let match = reHostnameFromCommonURL.exec(uri); if ( match !== null ) { return match[0].slice(8, -1); } @@ -168,6 +173,7 @@ domainFromHostname, domainFromURI, entityFromDomain, + entityFromHostname, hostnameFromNetworkURL, hostnameFromURI, isNetworkURI, diff -Nru ublock-origin-1.62.0+dfsg/src/js/url-net-filtering.js ublock-origin-1.67.0+dfsg/src/js/url-net-filtering.js --- ublock-origin-1.62.0+dfsg/src/js/url-net-filtering.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/url-net-filtering.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,10 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - import { LineIterator } from './text-utils.js'; import { decomposeHostname } from './uri-utils.js'; diff -Nru ublock-origin-1.62.0+dfsg/src/js/urlskip.js ublock-origin-1.67.0+dfsg/src/js/urlskip.js --- ublock-origin-1.62.0+dfsg/src/js/urlskip.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/urlskip.js 2025-10-25 19:32:51.000000000 +0000 @@ -121,7 +121,7 @@ } // URI component if ( step === '-uricomponent' ) { - urlout = self.decodeURIComponent(urlin); + urlout = decodeURIComponent(urlin); continue; } // Enable skip of blocked requests @@ -157,10 +157,9 @@ const urlfinal = new URL(urlout); if ( urlfinal.protocol !== 'https:' ) { if ( urlfinal.protocol !== 'http:' ) { return; } - urlout = urlout.replace('http', 'https'); } if ( blocked && redirectBlocked !== true ) { return; } return urlout; - } catch(x) { + } catch { } } diff -Nru ublock-origin-1.62.0+dfsg/src/js/utils.js ublock-origin-1.67.0+dfsg/src/js/utils.js --- ublock-origin-1.62.0+dfsg/src/js/utils.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/utils.js 2025-10-25 19:32:51.000000000 +0000 @@ -19,10 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - import µb from './background.js'; /******************************************************************************/ @@ -72,7 +68,7 @@ popupLoggerBox = JSON.parse( vAPI.localStorage.getItem('popupLoggerBox') ); - } catch(ex) { + } catch { } if ( popupLoggerBox !== undefined ) { details.box = popupLoggerBox; @@ -97,7 +93,7 @@ µb.getModifiedSettings = function(edit, orig = {}) { const out = {}; for ( const prop in edit ) { - if ( orig.hasOwnProperty(prop) && edit[prop] !== orig[prop] ) { + if ( Object.hasOwn(orig, prop) && edit[prop] !== orig[prop] ) { out[prop] = edit[prop]; } } @@ -106,7 +102,7 @@ µb.settingValueFromString = function(orig, name, s) { if ( typeof name !== 'string' || typeof s !== 'string' ) { return; } - if ( orig.hasOwnProperty(name) === false ) { return; } + if ( Object.hasOwn(orig, name) === false ) { return; } let r; switch ( typeof orig[name] ) { case 'boolean': diff -Nru ublock-origin-1.62.0+dfsg/src/js/wasm/README.md ublock-origin-1.67.0+dfsg/src/js/wasm/README.md --- ublock-origin-1.62.0+dfsg/src/js/wasm/README.md 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/wasm/README.md 2025-10-25 19:32:51.000000000 +0000 @@ -13,7 +13,7 @@ ### `wat2wasm` tool The `wat2wasm` tool can be downloaded from an official WebAssembly project: -. + ### `wat2wasm` tool online Binary files /srv/release.debian.org/tmp/En7nkbHWiS/ublock-origin-1.62.0+dfsg/src/js/wasm/biditrie.wasm and /srv/release.debian.org/tmp/loyMF0iGQH/ublock-origin-1.67.0+dfsg/src/js/wasm/biditrie.wasm differ diff -Nru ublock-origin-1.62.0+dfsg/src/js/wasm/biditrie.wat ublock-origin-1.67.0+dfsg/src/js/wasm/biditrie.wat --- ublock-origin-1.62.0+dfsg/src/js/wasm/biditrie.wat 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/wasm/biditrie.wat 2025-10-25 19:32:51.000000000 +0000 @@ -32,16 +32,16 @@ ;; ;; Memory layout, byte offset: ;; const HAYSTACK_START = 0; -;; const HAYSTACK_SIZE = 2048; // i32 / i8 -;; const HAYSTACK_SIZE_SLOT = HAYSTACK_SIZE >>> 2; // 512 / 2048 -;; const TRIE0_SLOT = HAYSTACK_SIZE_SLOT + 1; // 513 / 2052 -;; const TRIE1_SLOT = HAYSTACK_SIZE_SLOT + 2; // 514 / 2056 -;; const CHAR0_SLOT = HAYSTACK_SIZE_SLOT + 3; // 515 / 2060 -;; const CHAR1_SLOT = HAYSTACK_SIZE_SLOT + 4; // 516 / 2064 -;; const RESULT_L_SLOT = HAYSTACK_SIZE_SLOT + 5; // 517 / 2068 -;; const RESULT_R_SLOT = HAYSTACK_SIZE_SLOT + 6; // 518 / 2072 -;; const RESULT_IU_SLOT = HAYSTACK_SIZE_SLOT + 7; // 519 / 2076 -;; const TRIE0_START = HAYSTACK_SIZE_SLOT + 8 << 2; // 2080 +;; const HAYSTACK_SIZE = 8192; // i32 / i8 +;; const HAYSTACK_SIZE_SLOT = HAYSTACK_SIZE >>> 2; // 2048 / 8192 +;; const TRIE0_SLOT = HAYSTACK_SIZE_SLOT + 1; // 2049 / 8196 +;; const TRIE1_SLOT = HAYSTACK_SIZE_SLOT + 2; // 2050 / 8200 +;; const CHAR0_SLOT = HAYSTACK_SIZE_SLOT + 3; // 2051 / 8204 +;; const CHAR1_SLOT = HAYSTACK_SIZE_SLOT + 4; // 2052 / 8208 +;; const RESULT_L_SLOT = HAYSTACK_SIZE_SLOT + 5; // 2053 / 8212 +;; const RESULT_R_SLOT = HAYSTACK_SIZE_SLOT + 6; // 2054 / 8216 +;; const RESULT_IU_SLOT = HAYSTACK_SIZE_SLOT + 7; // 2055 / 8220 +;; const TRIE0_START = HAYSTACK_SIZE_SLOT + 8 << 2; // 8224 ;; ;; @@ -71,11 +71,11 @@ ;; const buf32 = this.buf32; ;; const buf8 = this.buf8; ;; const char0 = buf32[CHAR0_SLOT]; - i32.const 2060 + i32.const 8204 i32.load align=4 local.set $char0 ;; const aR = buf32[HAYSTACK_SIZE_SLOT]; - i32.const 2048 + i32.const 8192 i32.load align=4 local.set $aR ;; let al = ai; @@ -253,7 +253,7 @@ ;; const buf32 = this.buf32; ;; const buf8 = this.buf8; ;; const char0 = buf32[CHAR0_SLOT]; - i32.const 2060 + i32.const 8204 i32.load align=4 local.set $char0 block $matchFound @@ -433,15 +433,15 @@ ;; } end ;; this.buf32[RESULT_IU_SLOT] = iu; - i32.const 2076 + i32.const 8220 local.get $iu i32.store align=4 ;; this.buf32[RESULT_L_SLOT] = l; - i32.const 2068 + i32.const 8212 local.get $l i32.store align=4 ;; this.buf32[RESULT_R_SLOT] = r; - i32.const 2072 + i32.const 8216 local.get $r i32.store align=4 end ;; $succeed @@ -483,7 +483,7 @@ ;; const charCodes = this.buf8; ;; needleLeft += this.buf32[CHAR0_SLOT]; local.get $needleLeft - i32.const 2060 ;; CHAR0_SLOT memory address + i32.const 8204 ;; CHAR0_SLOT memory address i32.load align=4 ;; CHAR0 memory address i32.add ;; needle memory address local.tee $needleLeft @@ -559,7 +559,7 @@ br_if $fail ;; needleLeft += this.buf32[CHAR0_SLOT]; local.get $needleLeft - i32.const 2060 ;; CHAR0_SLOT memory address + i32.const 8204 ;; CHAR0_SLOT memory address i32.load align=4 ;; CHAR0 memory address i32.add ;; needle memory address local.tee $needleLeft @@ -659,7 +659,7 @@ br_if $fail ;; needleLeft += this.buf32[CHAR0_SLOT]; local.get $needleLeft - i32.const 2060 ;; CHAR0_SLOT memory address + i32.const 8204 ;; CHAR0_SLOT memory address i32.load align=4 ;; CHAR0 memory address i32.add ;; needle memory address local.tee $needleLeft diff -Nru ublock-origin-1.62.0+dfsg/src/js/whitelist.js ublock-origin-1.67.0+dfsg/src/js/whitelist.js --- ublock-origin-1.62.0+dfsg/src/js/whitelist.js 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/js/whitelist.js 2025-10-25 19:32:51.000000000 +0000 @@ -21,10 +21,8 @@ /* global CodeMirror, uBlockDashboard */ -'use strict'; - -import { i18n$ } from './i18n.js'; import { dom, qs$ } from './dom.js'; +import { i18n$ } from './i18n.js'; /******************************************************************************/ @@ -62,7 +60,7 @@ if ( reRegex.test(line) ) { try { new RegExp(line.slice(1, -1)); - } catch(ex) { + } catch { return 'error'; } return null; @@ -101,12 +99,12 @@ /******************************************************************************/ function getEditorText() { - let text = cmEditor.getValue().replace(/\s+$/, ''); - return text === '' ? text : text + '\n'; + const text = cmEditor.getValue().trimEnd(); + return text === '' ? text : `${text}\n`; } function setEditorText(text) { - cmEditor.setValue(text.replace(/\s+$/, '') + '\n'); + cmEditor.setValue(`${text.trimEnd()}\n`); } /******************************************************************************/ diff -Nru ublock-origin-1.62.0+dfsg/src/logger-ui.html ublock-origin-1.67.0+dfsg/src/logger-ui.html --- ublock-origin-1.62.0+dfsg/src/logger-ui.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/logger-ui.html 2025-10-25 19:32:51.000000000 +0000 @@ -3,12 +3,13 @@ + - + diff -Nru ublock-origin-1.62.0+dfsg/src/no-dashboard.html ublock-origin-1.67.0+dfsg/src/no-dashboard.html --- ublock-origin-1.62.0+dfsg/src/no-dashboard.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/no-dashboard.html 2025-10-25 19:32:51.000000000 +0000 @@ -3,6 +3,7 @@ + uBlock — About diff -Nru ublock-origin-1.62.0+dfsg/src/popup-fenix.html ublock-origin-1.67.0+dfsg/src/popup-fenix.html --- ublock-origin-1.62.0+dfsg/src/popup-fenix.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/popup-fenix.html 2025-10-25 19:32:51.000000000 +0000 @@ -4,11 +4,12 @@ + - + diff -Nru ublock-origin-1.62.0+dfsg/src/settings.html ublock-origin-1.67.0+dfsg/src/settings.html --- ublock-origin-1.62.0+dfsg/src/settings.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/settings.html 2025-10-25 19:32:51.000000000 +0000 @@ -3,6 +3,7 @@ + uBlock — Settings diff -Nru ublock-origin-1.62.0+dfsg/src/support.html ublock-origin-1.67.0+dfsg/src/support.html --- ublock-origin-1.62.0+dfsg/src/support.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/support.html 2025-10-25 19:32:51.000000000 +0000 @@ -3,6 +3,7 @@ + uBlock Origin — Support @@ -13,7 +14,7 @@ - + diff -Nru ublock-origin-1.62.0+dfsg/src/web_accessible_resources/epicker-ui.html ublock-origin-1.67.0+dfsg/src/web_accessible_resources/epicker-ui.html --- ublock-origin-1.62.0+dfsg/src/web_accessible_resources/epicker-ui.html 2025-02-09 18:18:39.000000000 +0000 +++ ublock-origin-1.67.0+dfsg/src/web_accessible_resources/epicker-ui.html 2025-10-25 19:32:51.000000000 +0000 @@ -16,7 +16,7 @@