diff --git a/.eslintrc.yml b/.eslintrc.yml index e9ff21ec0234c..d7db6e4e4f8bc 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -12,9 +12,11 @@ rules: - error - 4 - ignoredNodes: - - Program > IfStatement > BlockStatement + - 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 > * diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index f1ca168f9fba9..097d0eccd5979 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -10,5 +10,5 @@ contact_links: url: https://github.com/uBlockOrigin/uAssets/issues about: Report issues with filter lists or broken website functionality in the uAssets issue tracker. - name: uBO Lite (uBOL) Issues - url: https://github.com/uBlockOrigin/uBOL-issues/issues + url: https://github.com/uBlockOrigin/uBOL-home/issues about: Report issues specific to the Manifest Version 3 (MV3) variant in the uBOL issue tracker. diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5ce7af1212a4f..1d34c0242d012 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,9 +7,6 @@ on: permissions: contents: read -# I used the following project as template to get started: -# https://github.com/dessant/search-by-image/blob/master/.github/workflows/ci.yml - jobs: build: permissions: @@ -25,66 +22,33 @@ jobs: - name: Clone uAssets run: | tools/pull-assets.sh - # https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html - name: Get release information - id: release_info run: | - echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//} + echo "VERSION=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV + - name: Build MV2 packages + 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%/${{ steps.release_info.outputs.VERSION }}/g' RELEASE.HEAD.md >> release.body.txt + sed -e 's/%version%/${{ env.VERSION }}/g' RELEASE.HEAD.md >> release.body.txt - name: Create GitHub release id: create_release - uses: actions/create-release@v1 + uses: softprops/action-gh-release@v2 env: GITHUB_TOKEN: ${{ github.token }} with: - tag_name: ${{ steps.release_info.outputs.VERSION }} - release_name: ${{ steps.release_info.outputs.VERSION }} + tag_name: ${{ env.VERSION }} + name: ${{ env.VERSION }} draft: true prerelease: true body_path: release.body.txt - - name: Build MV2 packages - run: | - tools/make-chromium.sh ${{ steps.release_info.outputs.VERSION }} - tools/make-firefox.sh ${{ steps.release_info.outputs.VERSION }} - tools/make-thunderbird.sh ${{ steps.release_info.outputs.VERSION }} - tools/make-npm.sh ${{ steps.release_info.outputs.VERSION }} - - name: Upload Chromium package - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: dist/build/uBlock0_${{ steps.release_info.outputs.VERSION }}.chromium.zip - asset_name: uBlock0_${{ steps.release_info.outputs.VERSION }}.chromium.zip - asset_content_type: application/octet-stream - - name: Upload Firefox package - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: dist/build/uBlock0_${{ steps.release_info.outputs.VERSION }}.firefox.xpi - asset_name: uBlock0_${{ steps.release_info.outputs.VERSION }}.firefox.xpi - asset_content_type: application/octet-stream - - name: Upload Thunderbird package - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: dist/build/uBlock0_${{ steps.release_info.outputs.VERSION }}.thunderbird.xpi - asset_name: uBlock0_${{ steps.release_info.outputs.VERSION }}.thunderbird.xpi - asset_content_type: application/octet-stream - - name: Upload NodeJS package - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: dist/build/uBlock0_${{ steps.release_info.outputs.VERSION }}.npm.tgz - asset_name: uBlock0_${{ steps.release_info.outputs.VERSION }}.npm.tgz - asset_content_type: application/octet-stream + 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 --git a/.gitignore b/.gitignore index dee00e98d3b96..2c0e571513d19 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ *.bak *.pem +__pycache__/ +node_modules/ /dist/build/ /tmp/ diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/CHANGELOG.md b/CHANGELOG.md index b7d8d3d6ba7b6..95caa55a11a3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,126 @@ +- [Improve quote usage in filter options and scriptlets](https://github.com/gorhill/uBlock/commit/8ba71f09d7) +- [Improve `trusted-suppress-native-method` scriptlet](https://github.com/gorhill/uBlock/commit/7ed3470844) +- [Improve `trusted-replace-argument` scriptlet](https://github.com/gorhill/uBlock/commit/3417fe3d5d) +- [Block media elements unconditionally when max size is set to 0](https://github.com/gorhill/uBlock/commit/36db7f8327) + - Regression from +- [Visually separate scriptlet parameters in active line](https://github.com/gorhill/uBlock/commit/076e9fa73e) +- [Mitigate potentially delayed execution of scriptlets in Firefox](https://github.com/gorhill/uBlock/commit/b1a00145bd) +- [Improve `prevent-setTimeout`/`prevent-setInterval` scriptlets](https://github.com/gorhill/uBlock/commit/3b7fa79a68) +- [Improve `trusted-replace-argument` scriptlet](https://github.com/gorhill/uBlock/commit/adced29b5b) +- [Add `-safebase64` directive to `urlskip=` option](https://github.com/gorhill/uBlock/commit/bcc058eba7) +- [Improve `urlskip=` filter option](https://github.com/gorhill/uBlock/commit/77ed83ff2f) +- [Improve `spoof-css` scriptlet](https://github.com/gorhill/uBlock/commit/5f5e3d730f) +- [Improve `trusted-set-attr` scriptlet](https://github.com/gorhill/uBlock/commit/c8174d6032) +- [Add support for EasyList `{ remove: true }` cosmetic filter syntax](https://github.com/gorhill/uBlock/commit/ff5fc61753) +- [Keep moving related scriptlets into separate files](https://github.com/gorhill/uBlock/commit/e5a088738d) +- [Improve `prevent-xhr` scriptlet](https://github.com/gorhill/uBlock/commit/ce4908b341) +- [Improve `trusted-suppress-native-method` scriptlet](https://github.com/gorhill/uBlock/commit/41616df866) +- [Improve `set-cookie` scriptlet](https://github.com/gorhill/uBlock/commit/e613282698) + +---------- + +# 1.61.2 + +## Fixes / changes + +- [Better handle unexpected conditions when deserializing](https://github.com/gorhill/uBlock/commit/4c299bfca9) +- [Fix potential infinite async loop](https://github.com/gorhill/uBlock/commit/335d947c10) (issue found by @Rob--W) + +---------- + +# 1.61.0 + +## Fixes / changes + +- [Improve `prevent-refresh` scriptlet](https://github.com/gorhill/uBlock/commit/8884f259c1) +- [Improve `googlesyndication_adsbygoogle.js` scriptlet](https://github.com/gorhill/uBlock/commit/f645e8f0d2) +- [Offer ability to skip redirects in strict-blocked page](https://github.com/gorhill/uBlock/commit/20b54185fa) +- [Add `-blocked` directive to `urlskip=` option](https://github.com/gorhill/uBlock/commit/d04dc4c767) +- [Add `trusted-set-attr` scriptlet](https://github.com/gorhill/uBlock/commit/11ca4a3923) +- [Remove `64:ff9b:` as private network block](https://github.com/gorhill/uBlock/commit/2621c908c3) +- [Ensure `urlskip=` redirects only to `https:`](https://github.com/gorhill/uBlock/commit/32f27c5131) +- [Add support to `urlskip=` media resources](https://github.com/gorhill/uBlock/commit/ce9fc5dc14) +- [Add `-uricomponent` to `urlskip=` option](https://github.com/gorhill/uBlock/commit/01eebffc1f) +- [Add `forbidden`/`forever` as safe cookie values](https://github.com/gorhill/uBlock/commit/4d982d9972) (by @ryanbr) +- [Add regex extraction transformation step to `urlskip=` option](https://github.com/gorhill/uBlock/commit/c86ed5287b) +- [Improve `prevent-window-open` scriptlet](https://github.com/gorhill/uBlock/commit/85877b12ed) +- [Add support to parse Adguard's `[$domain=/.../]` regex-based modifier](https://github.com/gorhill/uBlock/commit/58bfe4c846) +- [Validate result type of XPath expressions](https://github.com/gorhill/uBlock/commit/c746633693) +- [Fix npm test suite](https://github.com/gorhill/uBlock/commit/818cb2d801) +- [Add ability to lookup parameter name in `urlskip=`](https://github.com/gorhill/uBlock/commit/64b2086ba4) +- [Mind that BroadcastChannel contructor can throw in Firefox](https://github.com/gorhill/uBlock/commit/6d2b3375f8) +- [Add `trusted-override-element-method` scriptlet](https://github.com/gorhill/uBlock/commit/95b0ce5e3a) +- [Add `trusted-prevent-dom-bypass` scriptlet](https://github.com/gorhill/uBlock/commit/1abc864742) +- [Improve `prevent-xhr` scriptlet; add `trusted-prevent-xhr` scriptlet](https://github.com/gorhill/uBlock/commit/fe49ced2ac) +- [Skip dns resolution when requests are proxied through http](https://github.com/gorhill/uBlock/commit/4305bfbdb1) +- [Blocking large media elements also prevents autoplay, regardless of size](https://github.com/gorhill/uBlock/commit/73ce4e6bcf) +- [Do not discard `!#else` block for unknown preprocessor tokens](https://github.com/gorhill/uBlock/commit/6cac645830) +- [Add ability to decode base64 in `urlskip=`](https://github.com/gorhill/uBlock/commit/e81e70937f) +- [Fix images not properly downloading on click](https://github.com/gorhill/uBlock/commit/aec0bd39e3) + +---------- + +# 1.60.0 + +## Fixes / changes + +- [Add advanced setting `dnsResolveEnabled`](https://github.com/gorhill/uBlock/commit/760b2ffce6) +- [Fix contextual menu quirks](https://github.com/gorhill/uBlock/commit/0a6dc47a72) +- [Fix exception thrown in `spoof-css` in Firefox](https://github.com/gorhill/uBlock/commit/11c3a16036) +- [Throttle down repeated scriptlet logging information](https://github.com/gorhill/uBlock/commit/e8f6f3ddff) +- [Improve scriptlet helper `proxy-apply`](https://github.com/gorhill/uBlock/commit/547fae4842) +- [Add an entry in _Report_ page for badware/phishing category](https://github.com/gorhill/uBlock/commit/e18a3707c7) +- [New static network filter option `urlskip=`](https://github.com/gorhill/uBlock/commit/266ec4894b) +- [Rewrite cname uncloaking code to account for new `ipaddress=` option](https://github.com/gorhill/uBlock/commit/6acf97bf51) +- [Avoid using dns.resolve() for proxied DNS resolution](https://github.com/gorhill/uBlock/commit/d5f14ffa32) +- [Add support for `lan`/`loopback` values to `ipaddress=` option](https://github.com/gorhill/uBlock/commit/030d7334e4) +- [New static network filter option `ipaddress=`](https://github.com/gorhill/uBlock/commit/c6dedd253f) +- [Add ability to quote static network option values](https://github.com/gorhill/uBlock/commit/20115697e5) +- [Improve `prevent-fetch` scriptlet](https://github.com/gorhill/uBlock/commit/e8202af11d) +- [Apply CSP/PP injections to `object` resources](https://github.com/gorhill/uBlock/commit/89f02098fd) +- [Improve `xml-prune` scriptlet](https://github.com/gorhill/uBlock/commit/c8307f58a3) +- [Add support for `application/dash+xml` in `replace=` option](https://github.com/gorhill/uBlock/commit/91125d29cf) +- [Add ability to directly evaluate static network filtering engine](https://github.com/gorhill/uBlock/commit/b7ed3b45ed) +- [Fix `prevent-window-open` for when logger is open](https://github.com/gorhill/uBlock/commit/f552f655cb) +- [Improve `prevent-window-open` scriptlet](https://github.com/gorhill/uBlock/commit/7f11d6216e) +- [Improve `validate-constant` scriptlet helper](https://github.com/gorhill/uBlock/commit/ae5dc6299e) +- [Improve `trusted-replace-outbound-text` scriptlet](https://github.com/gorhill/uBlock/commit/0dcb985601) +- [Improve `prevent-xhr` scriptlet](https://github.com/gorhill/uBlock/commit/3a249f395c) +- [Add noop resources for redirect purpose](https://github.com/gorhill/uBlock/commit/59a9a43a83) +- [Use helper function to lookup safe cookie values](https://github.com/gorhill/uBlock/commit/79e10323ad) +- [Add `checked`/`unchecked` to `set-cookie`](https://github.com/gorhill/uBlock/commit/3e2171f550) (by @ryanbr) +- [Add `allowed`/`denied` to `set-local-storage-item`](https://github.com/gorhill/uBlock/commit/41c2258f91) (by @ryanbr) +- [Fix plain exceptions not overriding block filters using `header=` option](https://github.com/gorhill/uBlock/commit/1cb660b94e) +- [Improve various scriptlets](https://github.com/gorhill/uBlock/commit/56dfdd2568) +- [Improve `href-sanitizer` scriptlet](https://github.com/gorhill/uBlock/commit/db3dc69bcc) +- [Improve `remove-attr.js` scriptlet](https://github.com/gorhill/uBlock/commit/fb037e97d0) +- [Improve `trusted-replace-node-text` scriptlet](https://github.com/gorhill/uBlock/commit/4f0d1301ab) + +---------- + +# 1.59.0 + +## Fixes / changes + +- [Improve `href-sanitizer` scriptlet](https://github.com/gorhill/uBlock/commit/84be9cde6d) +- [Improve `trusted-replace-node-text` scriptlet](https://github.com/gorhill/uBlock/commit/8afd9e233d) +- [Improve `set-constant` scriptlet](https://github.com/gorhill/uBlock/commit/77feb25c4d) +- [Improve `prevent-fetch` scriptlet](https://github.com/gorhill/uBlock/commit/e785b99338) +- [Improve `href-sanitizer` scriptlet](https://github.com/gorhill/uBlock/commit/66e3a1ad47) +- [Fix CSP/PP header injection in non-document resources](https://github.com/gorhill/uBlock/commit/c90f4933df) +- [Add `trusted-suppress-native-method` scriptlet](https://github.com/gorhill/uBlock/commit/97d11c03c2) +- [Add support for `$currentISODate$` in `trusted-set-cookie` scriptlet](https://github.com/gorhill/uBlock/commit/a3576ea651) +- [Add `essential` and `nonessential` to set-cookie](https://github.com/gorhill/uBlock/commit/37d31a82d8) (by @ryanbr) +- [Fix distance calculation in picker](https://github.com/gorhill/uBlock/commit/9569969b55) +- [Fix bad serialization of Date objects](https://github.com/gorhill/uBlock/commit/c154aaa69c) +- [Fix race condition when loading redirect/scriptlet resources](https://github.com/gorhill/uBlock/commit/896737d098) +- [Improve logging in `prevent-addEventListener` scriptlet](https://github.com/gorhill/uBlock/commit/8eb3b19c69) +- [Add `:matches-prop()` pseudo CSS operator](https://github.com/gorhill/uBlock/commit/aca7674bac) +- [Improve `set-cookie` scriptlet](https://github.com/gorhill/uBlock/commit/b4d8750f44) +- [Improve `trusted-replace-node-text` scriptlet](https://github.com/gorhill/uBlock/commit/cb0f65e035) +- [Improve `trusted-replace-(fetch|xhr)-response` scriptlets](https://github.com/gorhill/uBlock/commit/9072772f61) +- [Improve `prevent-addEventListener` scriptlet](https://github.com/gorhill/uBlock/commit/91ee5bdeae) +- [Add `isodate` as available placeholder for auto-comment](https://github.com/gorhill/uBlock/commit/d5208ee5dd) - [Improve `trusted-replace-outbound-text` scriptlet](https://github.com/gorhill/uBlock/commit/fa6740a059) - [Classify generic cosmetic filters with comma as highly generic](https://github.com/gorhill/uBlock/commit/8f81833efc) - [Raise max buffer size for response body filtering](https://github.com/gorhill/uBlock/commit/82a3992896) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2717e823dd9f4..ce2d70ee0b5dc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,31 +1,31 @@ # Contributions -Refer to the following sections to direct you to the appropriate destination. Thank you in advance for your help. +Please refer to the sections below to find the appropriate destination for your contributions. Thank you for your support! --- ### Translations -Help translate uBO via [Crowdin](https://crowdin.com/project/ublock). +You can help translate uBO via [Crowdin](https://crowdin.com/project/ublock). --- ### Reporting Issues -The issue tracker in this repository is deprecated. Use the links below to guide you to where you need to report your issue. +The issue tracker in this repository is deprecated. Use the links below to report your issues. #### Support Forum -For support, questions, or help, visit [/r/uBlockOrigin](https://www.reddit.com/r/uBlockOrigin/). +For support, questions, or assistance, please visit [/r/uBlockOrigin](https://www.reddit.com/r/uBlockOrigin/). #### Filter List Issues -Report issues with filter lists or broken website functionality in the [uAssets issue tracker](https://github.com/uBlockOrigin/uAssets/issues). +Report issues related to filter lists or broken website functionality in the [uAssets issue tracker](https://github.com/uBlockOrigin/uAssets/issues). #### uBlock Origin (uBO) Issues -Report issues with uBO in the [uBO issue tracker](https://github.com/uBlockOrigin/uBlock-issues/issues). +For issues specifically about uBO, please use the [uBO issue tracker](https://github.com/uBlockOrigin/uBlock-issues/issues). #### uBO Lite (uBOL) Issues -Report issues specific to the Manifest Version 3 (MV3) variant in the [uBOL issue tracker](https://github.com/uBlockOrigin/uBOL-issues/issues). +For issues related to the Manifest Version 3 (MV3) variant, report them in the [uBOL issue tracker](https://github.com/uBlockOrigin/uBOL-home/issues). diff --git a/Makefile b/Makefile index 194a3af43af08..b308dc4be1e0b 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,8 @@ # https://stackoverflow.com/a/6273809 run_options := $(filter-out $@,$(MAKECMDGOALS)) -.PHONY: all clean cleanassets test lint chromium opera firefox npm dig mv3 mv3-quick \ +.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 sources := $(wildcard assets/* assets/*/* dist/version src/* src/*/* src/*/*/* src/*/*/*/*) @@ -55,12 +56,16 @@ dig: dist/build/uBlock0.dig dig-snfe: dig cd dist/build/uBlock0.dig && npm run snfe $(run_options) -mv3-chromium: tools/make-mv3.sh $(sources) $(platform) +dist/build/uBOLite.chromium: tools/make-mv3.sh $(sources) $(platform) tools/make-mv3.sh chromium -mv3-firefox: tools/make-mv3.sh $(sources) $(platform) +mv3-chromium: dist/build/uBOLite.chromium + +dist/build/uBOLite.firefox: tools/make-mv3.sh $(sources) $(platform) tools/make-mv3.sh firefox +mv3-firefox: dist/build/uBOLite.firefox + mv3-quick: tools/make-mv3.sh $(sources) $(platform) tools/make-mv3.sh quick diff --git a/README.md b/README.md index 23e90367a14f8..18e6aacad9e6b 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,6 @@ uBlock Origin (uBO)

Get uBlock Origin for Firefox -Get uBlock Origin for Chromium Get uBlock Origin for Microsoft Edge Get uBlock Origin for Opera Get uBlock Origin for Thunderbird @@ -31,6 +30,13 @@ uBlock Origin (uBO) *** +

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

+ +*** + uBlock Origin (uBO) is a CPU and memory-efficient [wide-spectrum content blocker][Blocking] for Chromium and Firefox. It blocks ads, trackers, coin miners, popups, annoying anti-blockers, malware sites, etc., by default using [EasyList][EasyList], [EasyPrivacy][EasyPrivacy], [Peter Lowe's Blocklist][Peter Lowe's Blocklist], [Online Malicious URL Blocklist][Malicious Blocklist], and uBO [filter lists][uBO Filters]. There are many other lists available to block even more. Hosts files are also supported. uBO uses the EasyList filter syntax and [extends][Extended Syntax] the syntax to work with custom rules and filters. You may easily unselect any preselected filter lists if you think uBO blocks too much. For reference, Adblock Plus installs with only EasyList, ABP filters, and Acceptable Ads enabled by default. @@ -145,13 +151,13 @@ If you ever want to contribute something, think about the people working hard to [Performance]: https://www.debugbear.com/blog/chrome-extension-performance-2021#how-do-ad-blockers-and-privacy-tools-affect-browser-performance [EasyPrivacy]: https://easylist.to/#easyprivacy [Thunderbird]: https://addons.thunderbird.net/thunderbird/addon/ublock-origin/ -[Chrome Dev]: https://chrome.google.com/webstore/detail/ublock-origin-development/cgbcahbpdhpcegmbfconppldiemgcoii +[Chrome Dev]: https://chromewebstore.google.com/detail/ublock-origin-development/cgbcahbpdhpcegmbfconppldiemgcoii [EasyList]: https://easylist.to/#easylist [Mozilla]: https://addons.mozilla.org/addon/ublock-origin/ [Crowdin]: https://crowdin.com/project/ublock -[Chrome]: https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm +[Chrome]: https://chromewebstore.google.com/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm [Reddit]: https://www.reddit.com/r/uBlockOrigin/ -[Theft]: https://twitter.com/LeaVerou/status/518154828166725632 +[Theft]: https://x.com/LeaVerou/status/518154828166725632 [Opera]: https://addons.opera.com/extensions/details/ublock/ [Edge]: https://microsoftedge.microsoft.com/addons/detail/ublock-origin/odfafepnkmbhccpbejgmiehpchacaeak [NPM]: https://www.npmjs.com/package/@gorhill/ubo-core @@ -161,7 +167,6 @@ If you ever want to contribute something, think about the people working hard to [Nicole Rolls]: https://github.com/nicole-ashley - [Manual Installation]: https://github.com/gorhill/uBlock/tree/master/dist#install @@ -178,7 +183,6 @@ If you ever want to contribute something, think about the people working hard to [Beta]: https://github.com/gorhill/uBlock/blob/master/dist/README.md#for-beta-version [Wiki]: https://github.com/gorhill/uBlock/wiki - [Badge Localization]: https://d322cqt584bo4o.cloudfront.net/ublock/localized.svg @@ -189,4 +193,3 @@ If you ever want to contribute something, think about the people working hard to [Badge Edge]: https://img.shields.io/badge/dynamic/json?label=Edge&color=brightgreen&query=%24.averageRating&suffix=%2F%35&url=https%3A%2F%2Fmicrosoftedge.microsoft.com%2Faddons%2Fgetproductdetailsbycrxid%2Fodfafepnkmbhccpbejgmiehpchacaeak [Badge Issues]: https://img.shields.io/github/issues/uBlockOrigin/uBlock-issues [Badge NPM]: https://img.shields.io/npm/v/@gorhill/ubo-core - diff --git a/RELEASE.HEAD.md b/RELEASE.HEAD.md index ce149ad9c489e..986319b72bd8c 100644 --- a/RELEASE.HEAD.md +++ b/RELEASE.HEAD.md @@ -1,10 +1,12 @@ +[Commits to Master Since This Release](https://github.com/gorhill/uBlock/compare/%version%...master) -[Commits to master since this release](https://github.com/gorhill/uBlock/compare/%version%...master) +#### How to Install the Developer Build: -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). -- **Firefox**: Click [uBlock0_%version%.firefox.signed.xpi](https://github.com/gorhill/uBlock/releases/download/%version%/uBlock0_%version%.firefox.signed.xpi) - - [uBO works best on Firefox](https://github.com/gorhill/uBlock/wiki/uBlock-Origin-works-best-on-Firefox). -- **Chromium**: Install from the Chrome Web Store (CWS): . -- **Thunderbird**: Download [uBlock0_%version%.thunderbird.xpi](https://github.com/gorhill/uBlock/releases/download/%version%/uBlock0_%version%.thunderbird.xpi), then drag-n-drop it into Thunderbird's _Add-ons Manager_ pane (Thunderbird 91+ required) -- **Node.js**: 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). +- **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 --git a/assets/assets.dev.json b/assets/assets.dev.json index 354087f59c147..aa529d23614af 100644 --- a/assets/assets.dev.json +++ b/assets/assets.dev.json @@ -137,7 +137,7 @@ "tags": "ads", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/2_without_easylist.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "adguard-mobile": { "content": "filters", @@ -148,7 +148,7 @@ "ua": "mobile", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/11.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "easylist": { "content": "filters", @@ -175,7 +175,7 @@ "tags": "privacy", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/17.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "adguard-spyware": { "content": "filters", @@ -184,7 +184,7 @@ "title": "AdGuard Tracking Protection", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/3.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "block-lan": { "content": "filters", @@ -256,7 +256,7 @@ "tags": "annoyances cookies", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/18.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "ublock-cookies-adguard": { "content": "filters", @@ -325,7 +325,7 @@ "tags": "annoyances social", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/4.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "fanboy-social": { "content": "filters", @@ -368,7 +368,7 @@ "tags": "annoyances", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/19.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "adguard-mobile-app-banners": { "content": "filters", @@ -379,7 +379,7 @@ "tags": "annoyances mobile", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/20.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "adguard-other-annoyances": { "content": "filters", @@ -390,7 +390,7 @@ "tags": "annoyances", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/21.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "adguard-widgets": { "content": "filters", @@ -401,7 +401,7 @@ "tags": "annoyances", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/22.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "easylist-annoyances": { "content": "filters", @@ -584,8 +584,8 @@ "title": "🇪🇪ee: Eesti saitidele kohandatud filter", "tags": "ads estonian", "lang": "et", - "contentURL": "https://adblock.ee/list.php", - "supportURL": "https://adblock.ee/" + "contentURL": "https://adblock.ee/list.txt", + "supportURL": "https://adblock.ee" }, "FIN-0": { "content": "filters", @@ -622,9 +622,13 @@ "group": "regions", "off": true, "title": "🇭🇷hr 🇷🇸rs: Dandelion Sprout's Serbo-Croatian filters", - "tags": "ads croatian serbian", - "lang": "hr sr", - "contentURL": "https://raw.githubusercontent.com/DandelionSprout/adfilt/master/SerboCroatianList.txt", + "tags": "ads croatian serbian bosnian", + "lang": "bs hr sr", + "contentURL": [ + "https://raw.githubusercontent.com/DandelionSprout/adfilt/master/SerboCroatianList.txt", + "https://cdn.jsdelivr.net/gh/DandelionSprout/adfilt@master/SerboCroatianList.txt", + "https://cdn.statically.io/gl/DandelionSprout/adfilt/master/SerboCroatianList.txt" + ], "supportURL": "https://github.com/DandelionSprout/adfilt#readme" }, "HUN-0": { @@ -634,7 +638,7 @@ "title": "🇭🇺hu: hufilter", "tags": "ads hungarian", "lang": "hu", - "contentURL": "https://raw.githubusercontent.com/hufilter/hufilter/master/hufilter-ublock.txt", + "contentURL": "https://cdn.jsdelivr.net/gh/hufilter/hufilter@gh-pages/hufilter-ublock.txt", "supportURL": "https://github.com/hufilter/hufilter" }, "IDN-0": { @@ -681,8 +685,8 @@ "title": "🇮🇸is: Icelandic ABP List", "tags": "ads icelandic", "lang": "is", - "contentURL": "https://adblock.gardar.net/is.abp.txt", - "supportURL": "https://adblock.gardar.net/" + "contentURL": "https://raw.githubusercontent.com/brave/adblock-lists/master/custom/is.txt", + "supportURL": "https://github.com/brave/adblock-lists/issues" }, "ISR-0": { "content": "filters", @@ -713,7 +717,7 @@ "lang": "ja", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/7.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "KOR-1": { "content": "filters", @@ -768,7 +772,7 @@ "lang": "af fy nl", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/8.txt", "cdnURLs": null, - "supportURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "supportURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "NOR-0": { "content": "filters", @@ -778,9 +782,7 @@ "tags": "ads norwegian danish icelandic", "lang": "nb nn no da is", "contentURL": [ - "https://raw.githubusercontent.com/DandelionSprout/adfilt/master/NorwegianList.txt" - ], - "cdnURLs": [ + "https://raw.githubusercontent.com/DandelionSprout/adfilt/master/NorwegianList.txt", "https://cdn.jsdelivr.net/gh/DandelionSprout/adfilt@master/NorwegianList.txt", "https://cdn.statically.io/gl/DandelionSprout/adfilt/master/NorwegianList.txt" ], @@ -824,10 +826,11 @@ "RUS-0": { "content": "filters", "group": "regions", + "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", + "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", @@ -837,6 +840,22 @@ "supportURL": "https://forums.lanik.us/viewforum.php?f=102", "instructionURL": "https://forums.lanik.us/viewtopic.php?f=102&t=22512" }, + "RUS-1": { + "content": "filters", + "group": "regions", + "parent": "🇷🇺ru 🇺🇦ua 🇺🇿uz 🇰🇿kz: RU AdList", + "off": true, + "title": "🇷🇺ru 🇺🇦ua 🇺🇿uz 🇰🇿kz: RU AdList: Counters", + "tags": "ads belarusian беларуская kazakh tatar russian русский ukrainian українська uzbek be kk tt ru uk uz", + "contentURL": "https://raw.githubusercontent.com/easylist/ruadlist/master/cntblock.txt", + "cdnURLs": [ + "https://cdn.jsdelivr.net/gh/easylist/ruadlist@master/cntblock.txt", + "https://cdn.statically.io/gh/easylist/ruadlist/master/cntblock.txt", + "https://raw.githubusercontent.com/easylist/ruadlist/master/cntblock.txt" + ], + "supportURL": "https://forums.lanik.us/viewforum.php?f=102", + "instructionURL": "https://forums.lanik.us/viewtopic.php?f=102&t=22512" + }, "spa-0": { "content": "filters", "group": "regions", @@ -856,7 +875,7 @@ "lang": "an ast ca cak es eu gl gn trs pt quz", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/9.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "SVN-0": { "content": "filters", @@ -901,7 +920,17 @@ "lang": "tr", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/13.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" + }, + "UKR-0": { + "content": "filters", + "group": "regions", + "off": true, + "title": "🇺🇦ua: Ukrainian Filters", + "tags": "ads ukraine україна", + "lang": "uk", + "contentURL": "https://raw.githubusercontent.com/ukrainianfilters/lists/main/combined/uBO/uBO.txt", + "supportURL": "https://github.com/ukrainianfilters/lists" }, "VIE-1": { "content": "filters", diff --git a/assets/assets.json b/assets/assets.json index 44ccc1bad8fde..6449dbe932434 100644 --- a/assets/assets.json +++ b/assets/assets.json @@ -137,7 +137,7 @@ "tags": "ads", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/2_without_easylist.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "adguard-mobile": { "content": "filters", @@ -148,7 +148,7 @@ "ua": "mobile", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/11.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "easylist": { "content": "filters", @@ -175,7 +175,7 @@ "tags": "privacy", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/17.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "adguard-spyware": { "content": "filters", @@ -184,7 +184,7 @@ "title": "AdGuard Tracking Protection", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/3.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "block-lan": { "content": "filters", @@ -256,7 +256,7 @@ "tags": "annoyances cookies", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/18.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "ublock-cookies-adguard": { "content": "filters", @@ -325,7 +325,7 @@ "tags": "annoyances social", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/4.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "fanboy-social": { "content": "filters", @@ -368,7 +368,7 @@ "tags": "annoyances", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/19.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "adguard-mobile-app-banners": { "content": "filters", @@ -379,7 +379,7 @@ "tags": "annoyances mobile", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/20.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "adguard-other-annoyances": { "content": "filters", @@ -390,7 +390,7 @@ "tags": "annoyances", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/21.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "adguard-widgets": { "content": "filters", @@ -401,7 +401,7 @@ "tags": "annoyances", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/22.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "easylist-annoyances": { "content": "filters", @@ -584,8 +584,8 @@ "title": "🇪🇪ee: Eesti saitidele kohandatud filter", "tags": "ads estonian", "lang": "et", - "contentURL": "https://adblock.ee/list.php", - "supportURL": "https://adblock.ee/" + "contentURL": "https://adblock.ee/list.txt", + "supportURL": "https://adblock.ee" }, "FIN-0": { "content": "filters", @@ -622,9 +622,13 @@ "group": "regions", "off": true, "title": "🇭🇷hr 🇷🇸rs: Dandelion Sprout's Serbo-Croatian filters", - "tags": "ads croatian serbian", - "lang": "hr sr", - "contentURL": "https://raw.githubusercontent.com/DandelionSprout/adfilt/master/SerboCroatianList.txt", + "tags": "ads croatian serbian bosnian", + "lang": "bs hr sr", + "contentURL": [ + "https://raw.githubusercontent.com/DandelionSprout/adfilt/master/SerboCroatianList.txt", + "https://cdn.jsdelivr.net/gh/DandelionSprout/adfilt@master/SerboCroatianList.txt", + "https://cdn.statically.io/gl/DandelionSprout/adfilt/master/SerboCroatianList.txt" + ], "supportURL": "https://github.com/DandelionSprout/adfilt#readme" }, "HUN-0": { @@ -634,7 +638,7 @@ "title": "🇭🇺hu: hufilter", "tags": "ads hungarian", "lang": "hu", - "contentURL": "https://raw.githubusercontent.com/hufilter/hufilter/master/hufilter-ublock.txt", + "contentURL": "https://cdn.jsdelivr.net/gh/hufilter/hufilter@gh-pages/hufilter-ublock.txt", "supportURL": "https://github.com/hufilter/hufilter" }, "IDN-0": { @@ -681,8 +685,8 @@ "title": "🇮🇸is: Icelandic ABP List", "tags": "ads icelandic", "lang": "is", - "contentURL": "https://adblock.gardar.net/is.abp.txt", - "supportURL": "https://adblock.gardar.net/" + "contentURL": "https://raw.githubusercontent.com/brave/adblock-lists/master/custom/is.txt", + "supportURL": "https://github.com/brave/adblock-lists/issues" }, "ISR-0": { "content": "filters", @@ -713,7 +717,7 @@ "lang": "ja", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/7.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "KOR-1": { "content": "filters", @@ -768,7 +772,7 @@ "lang": "af fy nl", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/8.txt", "cdnURLs": null, - "supportURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "supportURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "NOR-0": { "content": "filters", @@ -778,9 +782,7 @@ "tags": "ads norwegian danish icelandic", "lang": "nb nn no da is", "contentURL": [ - "https://raw.githubusercontent.com/DandelionSprout/adfilt/master/NorwegianList.txt" - ], - "cdnURLs": [ + "https://raw.githubusercontent.com/DandelionSprout/adfilt/master/NorwegianList.txt", "https://cdn.jsdelivr.net/gh/DandelionSprout/adfilt@master/NorwegianList.txt", "https://cdn.statically.io/gl/DandelionSprout/adfilt/master/NorwegianList.txt" ], @@ -824,6 +826,7 @@ "RUS-0": { "content": "filters", "group": "regions", + "parent": "🇷🇺ru 🇺🇦ua 🇺🇿uz 🇰🇿kz: RU AdList", "off": true, "title": "🇷🇺ru 🇺🇦ua 🇺🇿uz 🇰🇿kz: RU AdList", "tags": "ads belarusian беларуская kazakh tatar russian русский ukrainian українська uzbek", @@ -837,6 +840,22 @@ "supportURL": "https://forums.lanik.us/viewforum.php?f=102", "instructionURL": "https://forums.lanik.us/viewtopic.php?f=102&t=22512" }, + "RUS-1": { + "content": "filters", + "group": "regions", + "parent": "🇷🇺ru 🇺🇦ua 🇺🇿uz 🇰🇿kz: RU AdList", + "off": true, + "title": "🇷🇺ru 🇺🇦ua 🇺🇿uz 🇰🇿kz: RU AdList: Counters", + "tags": "ads belarusian беларуская kazakh tatar russian русский ukrainian українська uzbek be kk tt ru uk uz", + "contentURL": "https://raw.githubusercontent.com/easylist/ruadlist/master/cntblock.txt", + "cdnURLs": [ + "https://cdn.jsdelivr.net/gh/easylist/ruadlist@master/cntblock.txt", + "https://cdn.statically.io/gh/easylist/ruadlist/master/cntblock.txt", + "https://raw.githubusercontent.com/easylist/ruadlist/master/cntblock.txt" + ], + "supportURL": "https://forums.lanik.us/viewforum.php?f=102", + "instructionURL": "https://forums.lanik.us/viewtopic.php?f=102&t=22512" + }, "spa-0": { "content": "filters", "group": "regions", @@ -856,7 +875,7 @@ "lang": "an ast ca cak es eu gl gn trs pt quz", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/9.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "SVN-0": { "content": "filters", @@ -901,7 +920,7 @@ "lang": "tr", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/13.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + "instructionURL": "https://adguard.com/kb/general/ad-filtering/adguard-filters/" }, "VIE-1": { "content": "filters", diff --git a/dist/README.md b/dist/README.md index 37622c5e96da9..98cb46dc06607 100644 --- a/dist/README.md +++ b/dist/README.md @@ -1,81 +1,103 @@ -## INSTALL +# INSTALL -### Chromium +## Chromium -- Download and unzip `ublock0.chromium.zip` ([latest release desirable](https://github.com/gorhill/uBlock/releases)). -- Rename the unzipped directory to `ublock` - - When you later update manually, replace the **content** of the `ublock` folder with the **content** of the latest zipped version. - - This will ensure that all the extension settings will be preserved - - As long as the extension loads **from same folder path from which it was originally installed**, all your settings will be preserved. -- Go to chromium/chrome *Extensions*. -- Click to check *Developer mode*. -- Click *Load unpacked extension...*. -- In the file selector dialog: - - Select the directory `ublock` which was created above. - - Click *Open*. +1. Download and unzip `ublock0.chromium.zip` ([latest release desirable](https://github.com/gorhill/uBlock/releases)). +2. Rename the unzipped directory to `ublock`. + - When you update manually, replace the **content** of the `ublock` folder with the **content** of the latest zipped version. This ensures all extension settings are preserved. + - As long as the extension loads from the same folder path as it was originally installed, your settings will be kept. +3. Open Chromium/Chrome and go to *Extensions*. +4. Click to enable *Developer mode*. +5. Click *Load unpacked extension...*. +6. In the file selector dialog: + - Select the `ublock` directory you created. + - Click *Open*. -The extension will now be available in your chromium/chromium-based browser. +The extension will now be available in your Chromium/Chromium-based browser. -Remember that you have to update manually also. For some users, updating manually is actually an advantage because: -- You can update when **you** want -- If ever a new version sucks, you can easily just re-install the previous one +**Note:** You must update manually. For some users, manual updates are beneficial because: +- You can update when **you** want. +- If a new version is unsatisfactory, you can easily reinstall the previous one. -### Firefox +## Firefox -Compatible with Firefox 52 and beyond. +Compatible with Firefox 52 and beyond. -#### For stable release version +### For Stable Release Version -This works only if you set `xpinstall.signatures.required` to `false` in `about:config`.[see "Add-on signing in Firefox"](https://support.mozilla.org/en-US/kb/add-on-signing-in-firefox) +This method only works if you set `xpinstall.signatures.required` to `false` in `about:config`.[see "Add-on signing in Firefox"](https://support.mozilla.org/en-US/kb/add-on-signing-in-firefox) -- Download `ublock0.firefox.xpi` ([latest release desirable](https://github.com/gorhill/uBlock/releases)). - - Right-click and choose _"Save As..."_. -- Drag and drop the previously downloaded `ublock0.firefox.xpi` into Firefox +1. Download `ublock0.firefox.xpi` ([latest release desirable](https://github.com/gorhill/uBlock/releases)). + - Right-click and choose _"Save As..."_. +2. Drag and drop the downloaded `ublock0.firefox.xpi` into Firefox. -#### For beta version +### For Beta Version - Click on `ublock0.firefox.signed.xpi` ([latest release desirable](https://github.com/gorhill/uBlock/releases)). -#### Location of uBO settings - -On Linux, the settings are saved in a JSON file located at `~/.mozilla/firefox/[profile name]/browser-extension-data/uBlock0@raymondhill.net/storage.js`. - -When you uninstall the extension, Firefox deletes that file, so all your settings are lost when you uninstall. - -### Firefox legacy - -Compatible with Firefox 24-56, [Pale Moon](https://www.palemoon.org/) and [SeaMonkey](http://www.seamonkey-project.org/). - -- Download `ublock0.firefox-legacy.xpi` ([latest release desirable](https://github.com/gorhill/uBlock-for-firefox-legacy/releases)). - - Right-click and select "Save Link As..." -- Drag and drop the previously downloaded `ublock0.firefox-legacy.xpi` into Firefox - -With Firefox 43 and beyond, you may need to toggle the setting `xpinstall.signatures.required` to `false` in `about:config`.[see "Add-on signing in Firefox"](https://support.mozilla.org/en-US/kb/add-on-signing-in-firefox) - -Your uBlock Origin settings are kept intact even after you uninstall the addon. - -On Linux, the settings are saved in a SQlite file located at `~/.mozilla/firefox/[profile name]/extension-data/ublock0.sqlite`. - -On Windows, the settings are saved in a SQlite file located at `%APPDATA%\Mozilla\Firefox\Profiles\[profile name]\extension-data\ublock0.sqlite`. - -### Build instructions (for developers) - -- Clone [uBlock repo](https://github.com/gorhill/uBlock): `git clone https://github.com/gorhill/uBlock.git` -- Set path to uBlock: `cd uBlock` -- The official version of uBO is in the `master` branch - - `git checkout master` -- Build the plugin: - - Chromium: `make chromium` - - Firefox: `make firefox` - - NPM package: `make npm` -- Load the result of the build into your browser: - - Chromium: - - Navigate to `chrome://extensions/` - - Check _"Developer mode"_ - - Click _"Load unpacked"_ - - Select `/uBlock/dist/build/uBlock0.chromium/` - - Firefox: - - Navigate to `about:debugging#/runtime/this-firefox` - - Click _"Load Temporary Add-on..."_ - - Select `/uBlock/dist/build/uBlock0.firefox/` - +### Location of uBO Settings + +On Linux, the settings are saved in a JSON file located at: +``` +~/.mozilla/firefox/[profile name]/browser-extension-data/uBlock0@raymondhill.net/storage.js +``` +When you uninstall the extension, Firefox deletes this file, and all your settings will be lost. + +### Firefox Legacy + +Compatible with Firefox 24-56, [Pale Moon](https://www.palemoon.org/), and [SeaMonkey](https://www.seamonkey-project.org/). + +1. Download `ublock0.firefox-legacy.xpi` ([latest release desirable](https://github.com/gorhill/uBlock-for-firefox-legacy/releases)). + - Right-click and select "Save Link As..." +2. Drag and drop the downloaded `ublock0.firefox-legacy.xpi` into Firefox. + +For Firefox 43 and beyond, you may need to toggle the setting `xpinstall.signatures.required` to `false` in `about:config`.[see "Add-on signing in Firefox"](https://support.mozilla.org/en-US/kb/add-on-signing-in-firefox) + +Your uBlock Origin settings are preserved even after uninstalling the addon. + +- On Linux, settings are saved in a SQLite file located at: +``` +~/.mozilla/firefox/[profile name]/extension-data/ublock0.sqlite +``` +- On Windows, settings are saved in a SQLite file located at: +``` +%APPDATA%\Mozilla\Firefox\Profiles\[profile name]\extension-data\ublock0.sqlite +``` + +## Build Instructions (for Developers) + +1. Clone the [uBlock repository](https://github.com/gorhill/uBlock): + ```bash + git clone https://github.com/gorhill/uBlock.git + ``` +2. Set the path to uBlock: + ```bash + cd uBlock + ``` +3. The official version of uBO is in the `master` branch: + ```bash + git checkout master + ``` +4. Build the plugin: + - Chromium: + ```bash + make chromium + ``` + - Firefox: + ```bash + make firefox + ``` + - NPM package: + ```bash + make npm + ``` +5. Load the result of the build into your browser: + - **Chromium:** + - Navigate to `chrome://extensions/` + - Check _"Developer mode"_ + - Click _"Load unpacked"_ + - Select `/uBlock/dist/build/uBlock0.chromium/` + - **Firefox:** + - Navigate to `about:debugging#/runtime/this-firefox` + - Click _"Load Temporary Add-on..."_ + - Select `/uBlock/dist/build/uBlock0.firefox/` diff --git a/dist/chromium/publish-stable.py b/dist/chromium/publish-stable.py new file mode 100755 index 0000000000000..d1adc14740783 --- /dev/null +++ b/dist/chromium/publish-stable.py @@ -0,0 +1,190 @@ +#!/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 --git a/dist/firefox/updates.json b/dist/firefox/updates.json index 66ccea57e3567..3d1dabb89b96e 100644 --- a/dist/firefox/updates.json +++ b/dist/firefox/updates.json @@ -3,9 +3,9 @@ "uBlock0@raymondhill.net": { "updates": [ { - "version": "1.58.1.3", + "version": "1.61.3.9", "browser_specific_settings": { "gecko": { "strict_min_version": "78.0" } }, - "update_link": "https://github.com/gorhill/uBlock/releases/download/1.58.1b3/uBlock0_1.58.1b3.firefox.signed.xpi" + "update_link": "https://github.com/gorhill/uBlock/releases/download/1.61.3b9/uBlock0_1.61.3b9.firefox.signed.xpi" } ] } diff --git a/dist/mv3/log.txt b/dist/mv3/log.txt deleted file mode 100644 index 122c47e95d023..0000000000000 --- a/dist/mv3/log.txt +++ /dev/null @@ -1,1584 +0,0 @@ -Version: 2023.8.19.910 -Secret: 72d7360bdd9117ff -============================ -Listset for 'default': - Fetching remote https://ublockorigin.github.io/uAssets/filters/filters.min.txt - Fetching remote https://ublockorigin.github.io/uAssets/filters/badware.txt - Fetching remote https://ublockorigin.github.io/uAssets/filters/privacy.min.txt - Fetching remote https://ublockorigin.github.io/uAssets/filters/unbreak.min.txt - Fetching remote https://ublockorigin.github.io/uAssets/filters/quick-fixes.txt - Fetching remote https://ublockorigin.github.io/uAssets/filters/ubol-filters.txt - Fetching remote https://ublockorigin.github.io/uAssets/thirdparties/easylist.txt - Fetching remote https://ublockorigin.github.io/uAssets/thirdparties/easyprivacy.txt - Fetching remote https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=1&mimetype=plaintext -Input filter count: 92855 - Accepted filter count: 91275 - Rejected filter count: 146 -Output rule count: 17561 - Pruning requestDomains: from 54014 to 53859 - Pruning requestDomains: from 2681 to 2675 - Pruning requestDomains: from 5929 to 5925 - Plain good: 16732 - Salvaged rule by ignoring 1 entity-based domain= option: erotic-beauties.com|hardsex.cc|rule34.top|sex-movies.biz|tube18.sexy|xvideos.name|booru.* - Salvaged rule by ignoring 19 entity-based domain= option: fullxh.com|hamsterix.*|megaxh.com|unlockxh4.com|xhadult2.com|xhadult3.com|xhadult4.com|xhadult5.com|xhamster.*|xhamster10.*|xhamster11.*|xhamster12.*|xhamster13.*|xhamster14.*|xhamster15.*|xhamster16.*|xhamster17.*|xhamster18.*|xhamster19.*|xhamster2.*|xhamster20.*|xhamster3.*|xhamster4.*|xhamster46.com|xhamster5.*|xhamster7.*|xhamster8.*|xhday.com|xhday1.com|xhmoon5.com|xhplanet1.com|xhplanet2.com|xhreal2.com|xhreal3.com|xhtab2.com|xhvictory.com|xhwebsite.com|xhwebsite2.com|xhwide1.com|xhwide8.com - Salvaged rule by ignoring 19 entity-based domain= option: fullxh.com|hamsterix.*|megaxh.com|unlockxh4.com|xhadult2.com|xhadult3.com|xhadult4.com|xhadult5.com|xhamster.*|xhamster10.*|xhamster11.*|xhamster12.*|xhamster13.*|xhamster14.*|xhamster15.*|xhamster16.*|xhamster17.*|xhamster18.*|xhamster19.*|xhamster2.*|xhamster20.*|xhamster3.*|xhamster4.*|xhamster46.com|xhamster5.*|xhamster7.*|xhamster8.*|xhday.com|xhday1.com|xhmoon5.com|xhplanet1.com|xhplanet2.com|xhreal2.com|xhreal3.com|xhtab2.com|xhvictory.com|xhwebsite.com|xhwebsite2.com|xhwide1.com|xhwide8.com - Salvaged rule by ignoring 1 entity-based domain= option: 8boobs.com|angelgals.com|babesexy.com|babesinporn.com|fooxybabes.com|hotbabeswanted.com|hotstunners.com|mainbabes.com|nakedbabes.club|nakedgirlsroom.com|nudebabes.sexy|pleasuregirl.net|rabbitsfun.com|sexybabes.club|sexybabesart.com|wantedbabes.com|silkengirl.* - Salvaged rule by ignoring 1 entity-based domain= option: web.de|gmx.* - Salvaged rule by ignoring 2 entity-based domain= option: vizcloud.*|vizcloud2.*|mcloud.to - Salvaged rule by ignoring 1 entity-based domain= option: 8boobs.com|babesinporn.com|fooxybabes.com|hotstunners.com|mainbabes.com|pleasuregirl.net|rabbitsfun.com|wantedbabes.com|silkengirl.* - Salvaged rule by ignoring 2 entity-based domain= option: dood.*|dooood.*|doods.pro - Salvaged rule by ignoring 1 entity-based domain= option: vtplay.net|vtplayer.net|vtube.to|vtbe.* - Salvaged rule by ignoring 1 entity-based domain= option: piraproxy.app|unblocksite.pw|theproxy.* - Salvaged rule by ignoring 1 entity-based domain= option: androidapks.biz|androidsite.net|animeonlinefree.org|animesite.net|computercrack.com|crackedsoftware.biz|crackfree.org|cracksite.info|downloadapk.info|downloadapps.info|downloadgames.info|downloadmusic.info|downloadsite.org|ebooksite.org|emulatorsite.com|fmovies24.com|freeflix.info|freemoviesu4.com|freesoccer.net|fseries.org|gamefast.org|gamesite.info|gostreamon.net|hindisite.net|isosite.org|macsite.info|mangasite.org|megamovies.org|moviefree2.com|moviesite.app|moviesx.org|musicsite.biz|patchsite.net|pdfsite.net|play1002.com|productkeysite.com|romsite.org|seriesite.net|siteapk.net|siteflix.org|sitegames.net|sitekeys.net|sitepdf.com|sitetorrent.com|softwaresite.net|superapk.org|supermovies.org|tvonlinesports.com|ultramovies.org|warezsite.net|watchmovies2.com|watchmoviesforfree.org|watchsite.net|youapk.net|sitesunblocked.* - Salvaged rule by ignoring 19 entity-based domain= option: fullxh.com|hamsterix.*|megaxh.com|unlockxh4.com|xhadult2.com|xhadult3.com|xhadult4.com|xhadult5.com|xhamster.*|xhamster10.*|xhamster11.*|xhamster12.*|xhamster13.*|xhamster14.*|xhamster15.*|xhamster16.*|xhamster17.*|xhamster18.*|xhamster19.*|xhamster2.*|xhamster20.*|xhamster3.*|xhamster4.*|xhamster46.com|xhamster5.*|xhamster7.*|xhamster8.*|xhday.com|xhday1.com|xhmoon5.com|xhplanet1.com|xhplanet2.com|xhreal2.com|xhreal3.com|xhtab2.com|xhvictory.com|xhwebsite.com|xhwebsite2.com|xhwide1.com|xhwide8.com - Salvaged rule by ignoring 19 entity-based domain= option: fullxh.com|hamsterix.*|megaxh.com|unlockxh4.com|xhadult2.com|xhadult3.com|xhadult4.com|xhadult5.com|xhamster.*|xhamster10.*|xhamster11.*|xhamster12.*|xhamster13.*|xhamster14.*|xhamster15.*|xhamster16.*|xhamster17.*|xhamster18.*|xhamster19.*|xhamster2.*|xhamster20.*|xhamster3.*|xhamster4.*|xhamster46.com|xhamster5.*|xhamster7.*|xhamster8.*|xhday.com|xhday1.com|xhmoon5.com|xhplanet1.com|xhplanet2.com|xhreal2.com|xhreal3.com|xhtab2.com|xhvictory.com|xhwebsite.com|xhwebsite2.com|xhwide1.com|xhwide8.com - Salvaged rule by ignoring 11 entity-based domain= option: clik.pw|1ink.cc|pornfay.*|picbaron.com|bit-url.com|upbam.org|sexvid.*|sexrura.pl|isohuntz.*|isohunt.*|isohunts.*|isohuntx.*|isohunthydra.*|isohunters.*|isohunting.*|myisohunt.*|torrentproject2.* - Salvaged rule by ignoring 19 entity-based domain= option: fullxh.com|hamsterix.*|megaxh.com|unlockxh4.com|xhadult2.com|xhadult3.com|xhadult4.com|xhadult5.com|xhamster.*|xhamster10.*|xhamster11.*|xhamster12.*|xhamster13.*|xhamster14.*|xhamster15.*|xhamster16.*|xhamster17.*|xhamster18.*|xhamster19.*|xhamster20.*|xhamster2.*|xhamster3.*|xhamster4.*|xhamster46.com|xhamster5.*|xhamster7.*|xhamster8.*|xhday.com|xhday1.com|xhmoon5.com|xhplanet1.com|xhplanet2.com|xhreal2.com|xhreal3.com|xhtab2.com|xhvictory.com|xhwebsite.com|xhwebsite2.com|xhwide1.com|xhwide8.com|webnovel.com - Salvaged rule by ignoring 1 entity-based domain= option: torrentproject2.*|click.allkeyshop.com - Salvaged rule by ignoring 3 entity-based domain= option: 0gomovies.*|cdn1.fastvid.co|cdnqq.net|gorockmovies.top|kokostream.net|movi.pk|ncdn22.xyz|netu.ac|player.msmini.*|vapley.* - Salvaged rule by ignoring 1 entity-based domain= option: isaidub1.com|isaidubhd.* - Salvaged rule by ignoring 1 entity-based domain= option: d3ward.github.io|direct-cloud.* - Salvaged rule by ignoring 1 entity-based domain= option: povvldeo.lol|povvldeo.* - Salvaged rule by ignoring 1 entity-based domain= option: pngit.live|pingit.* - Salvaged rule by ignoring 1 entity-based domain= option: enrt.eu|seulink.* - Salvaged rule by ignoring 1 entity-based domain= option: imgair.net|imgblaze.net|imgfrost.net|imgwia.buzz|pixsera.net|vestimage.site|pixlev.* - Salvaged rule by ignoring 1 entity-based domain= option: javthe.com|javfree.* - Salvaged rule by ignoring 1 entity-based domain= option: dropcoins.xyz|fastcoin.ga|faucetbr.tk|is2btc.com|swift4claim.com|quickclaims.* - Salvaged rule by ignoring 1 entity-based domain= option: olympicstreams.me|vipboxtv.* - Salvaged rule by ignoring 8 entity-based domain= option: adbull.org|zdnet.fr|imgsen.com|titsbox.com|senmanga.com|hitomi.la|mangovideo.*|bolly4umovies.*|gaybeeg.info|lovelynudez.com|classicpornbest.com|skymovieshd.*|topwwnews.com|elsfile.org|javdoe.to|javtc.*|webmusic.*|pics4you.net|kiwiexploits.com|pornxp.com|silverpic.com|suicidepics.com|tanix.net|freeuseporn.com|ukrainesmodels.com|freeadultcomix.com|xxxwebdlxxx.top|uproxy2.biz|crownimg.com|masaporn.xyz|dvdplay.*|mangaraw.org|imgstar.eu|imgsto.*|picdollar.com|pics4upload.com|amateurblog.tv|fashionblog.tv|latinblog.tv|silverblog.tv|tokyoblog.tv|xblog.tv|maxsport.one|sportz.football|streamgo.to|streamgoto.*|amazingstream.net|imwatchingmovies.com|zinchanmanga.com|weaksports.xyz|vidoza.co|vidoza.net|govid.co|up-4ever.net|abcvideo.cc|ouo.io|ouo.press|imgbox.com|pirateproxy.live|thehiddenbay.com|thepiratebay.org|thepiratebay10.org - Salvaged rule by ignoring 1 entity-based domain= option: ceesty.com|corneey.com|destyy.com|festyy.com|gestyy.com|hd-easyporn.com|bolly4umovies.*|pcgamez-download.com|torrentvhd.biz|lovelynudez.com|gayforit.eu|movieston.com|kiwiexploits.com|dropload.io|nsfwyoutube.com|pomvideo.cc|steampiay.cc|vidoza.co|vidoza.net|mixdrop.co|govid.co|up-4ever.net|abcvideo.cc|ouo.io|ouo.press|pirateproxy.live|thehiddenbay.com|thepiratebay10.org|opensubtitles.org - Salvaged rule by ignoring 19 entity-based domain= option: fullxh.com|hamsterix.*|megaxh.com|unlockxh4.com|xhadult2.com|xhadult3.com|xhadult4.com|xhadult5.com|xhamster.*|xhamster10.*|xhamster11.*|xhamster12.*|xhamster13.*|xhamster14.*|xhamster15.*|xhamster16.*|xhamster17.*|xhamster18.*|xhamster19.*|xhamster2.*|xhamster20.*|xhamster3.*|xhamster4.*|xhamster46.com|xhamster5.*|xhamster7.*|xhamster8.*|xhday.com|xhday1.com|xhmoon5.com|xhplanet1.com|xhplanet2.com|xhreal2.com|xhreal3.com|xhtab2.com|xhvictory.com|xhwebsite.com|xhwebsite2.com|xhwide1.com|xhwide8.com - Salvaged rule by ignoring 1 entity-based domain= option: cpmlink.net|mwpaste.com|lusthero.com|22pixx.xyz|goto.com.np|imgtorrnt.in|shrinkearn.com|9ig.de|pingit.im|pngit.live|elil.cc|vev.red|vidop.icu|vidup.io|tubepornclassic.com|ironysub.net|bolly4umovies.*|pcgamez-download.com|curto.win|freeadultcomix.com|xxxwebdlxxx.top|crownimg.com|pomvideo.cc|steampiay.cc|bc.vc|vidoza.co|vidoza.net|pirateproxy.live|thehiddenbay.com|thepiratebay.org|thepiratebay10.org - Salvaged rule by ignoring 1 entity-based domain= option: financemonk.net|dropgalaxy.* - Salvaged rule by ignoring 1 entity-based domain= option: financemonk.net|dropgalaxy.* - Salvaged rule by ignoring 2 entity-based domain= option: gentside.*|ohmymag.*|maxisciences.com - Salvaged rule by ignoring 2 entity-based domain= option: gentside.*|ohmymag.*|maxisciences.com - Salvaged rule by ignoring 2 entity-based domain= option: gentside.*|ohmymag.*|maxisciences.com - Salvaged rule by ignoring 2 entity-based domain= option: gentside.*|ohmymag.*|maxisciences.com - Salvaged rule by ignoring 2 entity-based domain= option: gentside.*|ohmymag.*|maxisciences.com - Salvaged rule by ignoring 1 entity-based domain= option: gentside.co.uk|gentside.com|gentside.de|maxisciences.com|ohmymag.co.uk|ohmymag.com|ohmymag.de|gentside.* - Salvaged rule by ignoring 1 entity-based domain= option: financemonk.net|dropgalaxy.* - Salvaged rule by ignoring 1 entity-based domain= option: financemonk.net|techthematter.xyz|dropgalaxy.* - Salvaged rule by ignoring 1 entity-based domain= option: ladbible.com|tyla.com|unilad.com|gamingbible.* - Salvaged rule by ignoring 1 entity-based domain= option: ladbible.com|tyla.com|unilad.com|gamingbible.* - Salvaged rule by ignoring 1 entity-based domain= option: educatiocenter.online|a2zapk.* - Salvaged rule by ignoring 2 entity-based domain= option: gentside.*|ohmymag.*|maxisciences.com - Salvaged rule by ignoring 1 entity-based domain= option: financemonk.net|dropgalaxy.* - Salvaged rule by ignoring 1 entity-based domain= option: ladbible.com|tyla.com|unilad.com|gamingbible.* - Salvaged rule by ignoring 1 entity-based domain= option: ladbible.com|tyla.com|unilad.com|gamingbible.* - Salvaged rule by ignoring 1 entity-based domain= option: educatiocenter.online|a2zapk.* - Salvaged rule by ignoring 1 entity-based domain= option: cbhours.com|pussyspace.* - Salvaged rule by ignoring 2 entity-based domain= option: acortalo.*|acortar.*|megadescarga.net - Salvaged rule by ignoring 2 entity-based domain= option: gentside.*|ohmymag.*|maxisciences.com - Salvaged rule by ignoring 5 entity-based domain= option: mylink.*|my1ink.*|myl1nk.*|myli3k.*|audiotools.pro|magesy.blog|magesypro.pro|audioztools.com|solvetube.*|promo-visits.site|satoshi-win.xyz|healdad.com|mobitaak.com|gamalk-sehetk.com|allcryptoz.net|crewbase.net|crewus.net|shinbhu.net|shinchu.net|thumb8.net|thumb9.net|topcryptoz.net|uniqueten.net|ultraten.net - Maybe good (regexes): 146 - redirect=: 342 - removeparams= (accepted/discarded): 34/12 - modifyHeaders=: 64 - Unsupported: 243 - Can't salvage rule with only entity-based domain= option: vidmoly.* - Can't salvage rule with only entity-based domain= option: megalink.* - Can't salvage rule with only entity-based domain= option: bg-gledai.* - FilterStrictParty: Strict partyness strict3p not supported - Can't salvage rule with only entity-based domain= option: nishankhatri.* - Can't salvage rule with only entity-based domain= option: oploverz.* - Can't salvage rule with only entity-based domain= option: mangaku.* - Can't salvage rule with only entity-based domain= option: nekopoi.* - Can't salvage rule with only entity-based domain= option: vinaurl.* - Can't salvage rule with only entity-based domain= option: komikcast.* - Can't salvage rule with only entity-based domain= option: movs4u.* - Can't salvage rule with only entity-based domain= option: movieon21.* - Can't salvage rule with only entity-based domain= option: aagmaal.* - Can't salvage rule with only entity-based domain= option: otakudesu.* - Can't salvage rule with only entity-based domain= option: myflixer.* - FilterStrictParty: Strict partyness strict3p not supported - Can't salvage rule with only entity-based domain= option: yts.* - regexFilter is not RE2-compatible: \/[a-z]{4,}\/(?!holly7)(?!siksik7)[0-9a-z]{3,}\d\.\d{1,2}\.\d{1,2}\.[0-9a-f]{32}\.js$ - Can't salvage rule with only entity-based domain= option: ouo.* - Can't salvage rule with only entity-based domain= option: dewimg.*|imgtown.*|imgviu.*|mazpic.*|outletpic.*|picrok.* - Can't salvage rule with only entity-based domain= option: vinaurl.* - Can't salvage rule with only entity-based domain= option: mirrorace.* - Can't salvage rule with only entity-based domain= option: the-voice-of-germany.* - Can't salvage rule with only entity-based domain= option: linkvertise.* - regexFilter is not RE2-compatible: ^https?:\/\/a\.[-0-9a-z]{4,21}\.[a-z]{2,5}\/(?=[a-z]*[0-9A-Z])[0-9a-zA-Z]{5,7}\.js$ - regexFilter is not RE2-compatible: ^https?:\/\/asg\.[-0-9a-z]{4,21}\.[a-z]{2,5}\/(?=[a-z]{0,6}[0-9A-Z])[0-9a-zA-Z]{7}\.js$ - regexFilter is not RE2-compatible: ^https?:\/\/pre\.[0-9a-z]{6,12}\.[a-z]{3,4}\/(?=[a-z]{0,6}[0-9A-Z])[0-9a-zA-Z]{7}\.js$ - regexFilter is not RE2-compatible: ^https?:\/\/oi\.[0-9a-z]{6,12}\.[a-z]{3}\/(?=[a-z]{0,6}[0-9A-Z])[0-9a-zA-Z]{7}\.js$ - Can't salvage rule with only entity-based domain= option: vegamovies.* - Can't salvage rule with only entity-based domain= option: waaaw.*|waaw.* - Can't salvage rule with only entity-based domain= option: vizcloud.*|vizcloud2.* - FilterStrictParty: Strict partyness strict3p not supported - Can't salvage rule with only entity-based domain= option: sexvid.* - Can't salvage rule with only entity-based domain= option: slreamplay.* - Can't salvage rule with only entity-based domain= option: sexwebvideo.* - Can't salvage rule with only entity-based domain= option: dutchycorp.* - regexFilter is not RE2-compatible: ^https:\/\/(?:www\d\.)?[-a-z]{6,}\.(?:com|info|net|org)\/(?=[-_a-zA-Z]{0,42}\d)(?=[-_0-9a-z]{0,42}[A-Z])[-_0-9a-zA-Z]{43}\/\?cid=[-_0-9a-zA-Z]{10,36}(?:&qs\d=\S+)?&(?:s|pub)id=[-_0-9a-z{}]{1,32}(?:&s=0\.\d+)?(?:#\S+)?$ - regexFilter is not RE2-compatible: ^https:\/\/(?:www\d\.)?[-a-z]{6,}\.(?:com|info|net|org)\/(?=[-_a-zA-Z]{0,42}\d)(?=[-_0-9a-z]{0,42}[A-Z])[-_0-9a-zA-Z]{43}\/\?(?:pub|s)id=[-_0-9a-z{}]{1,32}(?:&qs\d=\S+)?&cid=[-_0-9a-zA-Z]{10,36}(?:&s=0\.\d+)?(?:#\S+)?$ - Can't salvage rule with only entity-based domain= option: 1337x.*|1337x.g3g.*|unblockit.*|x1337x.* - regexFilter is not RE2-compatible: \/img\/(?!new).+\.gif - FilterStrictParty: Strict partyness strict1p not supported - Can't salvage rule with only entity-based domain= option: slreamplay.* - Can't salvage rule with only entity-based domain= option: pouvideo.*|povvideo.*|povw1deo.*|povwideo.*|powv1deo.*|powvibeo.*|powvideo.*|powvldeo.* - Can't salvage rule with only entity-based domain= option: pouvideo.*|povvideo.*|povw1deo.*|povwideo.*|powv1deo.*|powvibeo.*|powvideo.*|powvldeo.* - Can't salvage rule with only entity-based domain= option: strcloud.*|streamta.*|streamtape.*|strtape.*|strtapeadblock.*|strtpe.* - Can't salvage rule with only entity-based domain= option: bigkickass.*|kat.*|kat2.*|katbay.*|katfreak.*|kathydra.*|katkickass.*|katkickass.*|kattracker.*|kick4ss.*|kickass-usa.*|kickass.*|kickass2.*|kickassaustralia.*|kickassbay.*|kickassdb.*|kickassfull.*|kickassgo.*|kickasshydra.*|kickassindia.*|kickasskat.*|kickassminds.*|kickassmovies.*|kickasspk.*|kickasst.*|kickasstorrents.*|kickasstorrents2.*|kickasstracker.*|kickasstrusty.*|kickassuk.*|kickassunlocked.*|kickassz.*|kkat.*|kkickass.*|thekat.*|thekickass.*|topkickass.*|torrentkat.*|torrentskickass.* - Can't salvage rule with only entity-based domain= option: isohunt.*|isohunters.*|isohunthydra.*|isohunting.*|isohunts.*|isohuntx.*|isohuntz.*|myisohunt.* - FilterStrictParty: Strict partyness strict1p not supported - Can't salvage rule with only entity-based domain= option: uptomega.* - Can't salvage rule with only entity-based domain= option: uplinkto.* - Can't salvage rule with only entity-based domain= option: link1s.* - Can't salvage rule with only entity-based domain= option: moviesda1.* - Can't salvage rule with only entity-based domain= option: dloader.* - Can't salvage rule with only entity-based domain= option: isaidub.* - Can't salvage rule with only entity-based domain= option: zone-telechargement.* - Can't salvage rule with only entity-based domain= option: earnload.* - regexFilter is not RE2-compatible: ^https?:\/\/[a-z]{7,16}\.com?\/(?=[+\/0-9a-zA-Z]*\+)(?=[+\/a-zA-Z]*\d)(?=[+\/0-9a-z]*[A-Z])[+\/0-9a-zA-Z]{140,}$ - regexFilter is not RE2-compatible: ^https?:\/\/[a-z]{7,16}\.org\/(?=[+\/0-9a-zA-Z]*\+)(?=[+\/a-zA-Z]*\d)(?=[+\/0-9a-z]*[A-Z])[+\/0-9a-zA-Z]{140,}$ - Can't salvage rule with only entity-based domain= option: torlock.*|torlock2.* - Can't salvage rule with only entity-based domain= option: vipleague.* - Can't salvage rule with only entity-based domain= option: my1ink.*|myl1nk.*|myli3k.*|mylink.* - Can't salvage rule with only entity-based domain= option: sxyprn.* - Can't salvage rule with only entity-based domain= option: palimas.* - Can't salvage rule with only entity-based domain= option: vjav.* - Can't salvage rule with only entity-based domain= option: linkshorts.* - Can't salvage rule with only entity-based domain= option: mazpic.* - Can't salvage rule with only entity-based domain= option: picrok.* - Can't salvage rule with only entity-based domain= option: imgviu.* - Can't salvage rule with only entity-based domain= option: outletpic.* - Can't salvage rule with only entity-based domain= option: dewimg.* - Can't salvage rule with only entity-based domain= option: imgtown.* - Can't salvage rule with only entity-based domain= option: oploverz.* - Can't salvage rule with only entity-based domain= option: readcomiconline.* - Can't salvage rule with only entity-based domain= option: adsrt.* - Can't salvage rule with only entity-based domain= option: animeflv.* - Can't salvage rule with only entity-based domain= option: kiss-anime.* - Can't salvage rule with only entity-based domain= option: japscan.* - Can't salvage rule with only entity-based domain= option: downloadhub.* - Can't salvage rule with only entity-based domain= option: 9xbuddy.* - Can't salvage rule with only entity-based domain= option: viprow.* - Can't salvage rule with only entity-based domain= option: anitube.* - Can't salvage rule with only entity-based domain= option: mixdroop.*|mixdrop.*|mixdrp.* - Can't salvage rule with only entity-based domain= option: dramacool9.* - Can't salvage rule with only entity-based domain= option: hdfriday.* - Can't salvage rule with only entity-based domain= option: extramovies.* - Can't salvage rule with only entity-based domain= option: atomixhq.*|pctfenix.* - Can't salvage rule with only entity-based domain= option: shortearn.* - Can't salvage rule with only entity-based domain= option: okstream.* - Can't salvage rule with only entity-based domain= option: megavideo.* - Can't salvage rule with only entity-based domain= option: tmearn.* - Can't salvage rule with only entity-based domain= option: leechall.* - Can't salvage rule with only entity-based domain= option: allcalidad.* - Can't salvage rule with only entity-based domain= option: movieshub.* - Can't salvage rule with only entity-based domain= option: dailysport.* - Can't salvage rule with only entity-based domain= option: mkvcinemas.* - Can't salvage rule with only entity-based domain= option: pelispedia.* - Can't salvage rule with only entity-based domain= option: linkviet.* - Can't salvage rule with only entity-based domain= option: btdb.* - Can't salvage rule with only entity-based domain= option: animesvision.* - Can't salvage rule with only entity-based domain= option: miniurl.* - Can't salvage rule with only entity-based domain= option: uploadhub.* - Can't salvage rule with only entity-based domain= option: bollyflix.* - Can't salvage rule with only entity-based domain= option: veranime.*|verhentai.* - Can't salvage rule with only entity-based domain= option: shortzzy.* - Can't salvage rule with only entity-based domain= option: xtits.* - Can't salvage rule with only entity-based domain= option: shorttey.* - Can't salvage rule with only entity-based domain= option: hdmovieplus.* - Can't salvage rule with only entity-based domain= option: img4fap.* - Can't salvage rule with only entity-based domain= option: elitetorrent.* - Can't salvage rule with only entity-based domain= option: lite-link.* - Can't salvage rule with only entity-based domain= option: adcorto.* - Can't salvage rule with only entity-based domain= option: streamhub.* - Can't salvage rule with only entity-based domain= option: 720pstream.* - Can't salvage rule with only entity-based domain= option: toonanime.* - Can't salvage rule with only entity-based domain= option: buffstreams.* - Can't salvage rule with only entity-based domain= option: cinemakottaga.* - Can't salvage rule with only entity-based domain= option: hog.* - Can't salvage rule with only entity-based domain= option: samehadaku.* - Can't salvage rule with only entity-based domain= option: atishmkv.* - Can't salvage rule with only entity-based domain= option: watchomovies.* - Can't salvage rule with only entity-based domain= option: hdhub4u.* - Can't salvage rule with only entity-based domain= option: livetvon.* - Can't salvage rule with only entity-based domain= option: sports-stream.* - regexFilter is not RE2-compatible: ^https?:\/\/[0-9a-z]{4,8}\.autos\/(?=[a-z]{0,6}[0-9A-Z])[0-9a-zA-Z]{7}\.js$ - regexFilter is not RE2-compatible: ^https?:\/\/[0-9a-z]{4,8}\.beauty\/(?=[a-z]{0,6}[0-9A-Z])[0-9a-zA-Z]{7}\.js$ - regexFilter is not RE2-compatible: ^https?:\/\/[0-9a-z]{4,8}\.lol\/(?=[a-z]{0,6}[0-9A-Z])[0-9a-zA-Z]{7}\.js$ - regexFilter is not RE2-compatible: ^https?:\/\/[0-9a-z]{4,8}\.mom\/(?=[a-z]{0,6}[0-9A-Z])[0-9a-zA-Z]{7}\.js$ - regexFilter is not RE2-compatible: ^https?:\/\/[0-9a-z]{4,8}\.pro\/(?=[a-z]{0,6}[0-9A-Z])[0-9a-zA-Z]{7}\.js$ - regexFilter is not RE2-compatible: ^https?:\/\/[0-9a-z]{4,8}\.xyz\/(?=[a-z]{0,6}[0-9A-Z])[0-9a-zA-Z]{7}\.js$ - regexFilter is not RE2-compatible: ^https?:\/\/[a-z]{8,15}\.com?\/(?=[0-9a-zA-Z]*%)(?=[%a-zA-Z]*\d)(?=[%0-9a-z]*[A-Z])[%0-9a-zA-Z]{170,}$ - regexFilter is not RE2-compatible: ^https:\/\/(?:[a-z]{2}\.)?[a-z]{7,14}\.com\/r(?=[a-z]*[0-9A-Z])[0-9A-Za-z]{10,16}\/[A-Za-z]{5}$ - Can't salvage rule with only entity-based domain= option: sdmoviespoint.* - Can't salvage rule with only entity-based domain= option: torrentgalaxy.* - regexFilter is not RE2-compatible: ^https:\/\/[0-9a-z]{7,25}\.com\/v2(?:\/0\/)?(?=[-_0-9a-z]{0,84}[A-Z])(?=[-_a-zA-Z]{0,84}[0-9])[-_0-9a-zA-Z]{54,85}(#\?v=[0-9a-f]{32})?$ - Can't salvage rule with only entity-based domain= option: mazpic.* - Can't salvage rule with only entity-based domain= option: picrok.* - Can't salvage rule with only entity-based domain= option: imgviu.* - Can't salvage rule with only entity-based domain= option: outletpic.* - Can't salvage rule with only entity-based domain= option: dewimg.* - Can't salvage rule with only entity-based domain= option: imgtown.* - Can't salvage rule with only entity-based domain= option: btdb.* - regexFilter is not RE2-compatible: ^https?:\/\/(?:[a-z]{2}\.)?[0-9a-z]{7,16}\.com\/[a-z](?=[a-z]{0,25}[0-9A-Z])[0-9a-zA-Z]{3,26}\/(?:[1-6]\d{4}|[3-9]\d{3})\??(?:_=\d+|v=\d)?$ - regexFilter is not RE2-compatible: ^https?:\/\/(?:[a-z]{2}\.)?[0-9a-z]{7,16}\.website\/[a-z](?=[a-z]{0,25}[0-9A-Z])[0-9a-zA-Z]{3,26}\/(?:[1-6]\d{4}|[3-9]\d{3})\??(?:_=\d+|v=\d)?$ - regexFilter is not RE2-compatible: ^https:\/\/[0-9a-z]{7,25}\.com\/v2(?:\/0\/)?(?=[-_0-9a-z]{0,84}[A-Z])(?=[-_a-zA-Z]{0,84}[0-9])[-_0-9a-zA-Z]{54,85}(#\?v=[0-9a-f]{32})?$ - Can't salvage rule with only entity-based domain= option: sxyprn.* - Can't salvage rule with only entity-based domain= option: txxx.* - Can't salvage rule with only entity-based domain= option: mazpic.* - Can't salvage rule with only entity-based domain= option: picrok.* - Can't salvage rule with only entity-based domain= option: imgviu.* - Can't salvage rule with only entity-based domain= option: outletpic.* - Can't salvage rule with only entity-based domain= option: dewimg.* - Can't salvage rule with only entity-based domain= option: imgtown.* - Can't salvage rule with only entity-based domain= option: pouvideo.*|povvideo.*|povvldeo.*|povw1deo.*|povwideo.*|powv1deo.*|powvibeo.*|powvideo.*|powvldeo.* - Can't salvage rule with only entity-based domain= option: btdb.* - regexFilter is not RE2-compatible: ^https?:\/\/(?:[a-z]{2}\.)?[0-9a-z]{7,16}\.com\/[a-z](?=[a-z]{0,25}[0-9A-Z])[0-9a-zA-Z]{3,26}\/(?:[1-6]\d{4}|[3-9]\d{3})\??(?:_=\d+|v=\d)?$ - regexFilter is not RE2-compatible: ^https?:\/\/(?:[a-z]{2}\.)?[0-9a-z]{7,16}\.website\/[a-z](?=[a-z]{0,25}[0-9A-Z])[0-9a-zA-Z]{3,26}\/(?:[1-6]\d{4}|[3-9]\d{3})\??(?:_=\d+|v=\d)?$ - Can't salvage rule with only entity-based domain= option: xtits.* - Can't salvage rule with only entity-based domain= option: animesa.* - regexFilter is not RE2-compatible: ^https?:\/\/[a-z]{7,16}\.com?\/(?=[+\/0-9a-zA-Z]*\+)(?=[+\/a-zA-Z]*\d)(?=[+\/0-9a-z]*[A-Z])[+\/0-9a-zA-Z]{400,}$ - regexFilter is not RE2-compatible: ^https?:\/\/[a-z]{7,16}\.org\/(?=[+\/0-9a-zA-Z]*\+)(?=[+\/a-zA-Z]*\d)(?=[+\/0-9a-z]*[A-Z])[+\/0-9a-zA-Z]{400,}$ - regexFilter is not RE2-compatible: ^https:\/\/[a-z]{7}\.com\/sub\/(?=[a-z]{0,9}[0-9A-Z])[0-9A-Za-z]{10}$ - Can't salvage rule with only entity-based domain= option: hqq.* - Can't salvage rule with only entity-based domain= option: bloomberg.* - Can't salvage rule with only entity-based domain= option: my1ink.*|myl1nk.*|myli3k.*|mylink.* - Can't salvage rule with only entity-based domain= option: my1ink.*|myl1nk.*|myli3k.*|mylink.* - Can't salvage rule with only entity-based domain= option: hqq.* - Can't salvage rule with only entity-based domain= option: einthusan.* - Can't salvage rule with only entity-based domain= option: gentside.*|ohmymag.* - Can't salvage rule with only entity-based domain= option: gentside.*|ohmymag.* - Can't salvage rule with only entity-based domain= option: pasty.* - Can't salvage rule with only entity-based domain= option: pasty.* - Can't salvage rule with only entity-based domain= option: wstream.* - Can't salvage rule with only entity-based domain= option: viafree.* - Can't salvage rule with only entity-based domain= option: hotfrog.* - Can't salvage rule with only entity-based domain= option: goodstream.* - Can't salvage rule with only entity-based domain= option: now.* - Can't salvage rule with only entity-based domain= option: bloomberg.* - Can't salvage rule with only entity-based domain= option: bloomberg.* - Can't salvage rule with only entity-based domain= option: bloomberg.* - Can't salvage rule with only entity-based domain= option: allestoringen.*|downdetector.*|xn--allestrungen-9ib.* - Can't salvage rule with only entity-based domain= option: allestoringen.*|downdetector.*|xn--allestrungen-9ib.* - Can't salvage rule with only entity-based domain= option: allestoringen.*|downdetector.*|xn--allestrungen-9ib.* - Can't salvage rule with only entity-based domain= option: tube8.* - Can't salvage rule with only entity-based domain= option: audible.* - Can't salvage rule with only entity-based domain= option: savethechildren.* - Can't salvage rule with only entity-based domain= option: discoveryplus.* - Can't salvage rule with only entity-based domain= option: viafree.* - Can't salvage rule with only entity-based domain= option: streamingcommunity.* - Can't salvage rule with only entity-based domain= option: streamingcommunity.* - Can't salvage rule with only entity-based domain= option: filepress.* - Can't salvage rule with only entity-based domain= option: bloomberg.* - Can't salvage rule with only entity-based domain= option: soap2day.* - Can't salvage rule with only entity-based domain= option: soap2day.* - Can't salvage rule with only entity-based domain= option: pussyspace.* - Can't salvage rule with only entity-based domain= option: pussyspace.* - Can't salvage rule with only entity-based domain= option: pussyspace.* - Can't salvage rule with only entity-based domain= option: pussyspace.* - Can't salvage rule with only entity-based domain= option: pussyspace.* - Can't salvage rule with only entity-based domain= option: pussyspace.* - Can't salvage rule with only entity-based domain= option: slreamplay.* - Can't salvage rule with only entity-based domain= option: pouvideo.*|povvideo.*|povw1deo.*|povwideo.*|powv1deo.*|powvibeo.*|powvideo.*|powvldeo.* - Unsupported regex-based removeParam: /utm_source|utm_campaign|utm_content/ - Unsupported regex-based removeParam: /utm_source|utm_campaign|utm_content/ - Unsupported regex-based removeParam: /utm_source|utm_campaign|utm_content|utm_term|wr/ - Unpatchable redirect filter: abp-resource:blank-mp4 - Unpatchable redirect filter: abp-resource:blank-mp4 - Unsupported regex-based removeParam: /^\/_ui\/desktop\/common\/js\/uiAnalytics\// - Can't salvage rule with only entity-based domain= option: 1movies.* - Can't salvage rule with only entity-based domain= option: 1movies.* - Unsupported regex-based removeParam: /^ad/ - Unsupported regex-based removeParam: /^ad/ - Can't salvage rule with only entity-based domain= option: discoveryplus.* - Unsupported regex-based removeParam: /^(cookie|ga_|u_)/ - Unsupported regex-based removeParam: /^((?!SMIL|formats).)*$/ - Unsupported regex-based removeParam: /^((?!formats|profile).)*$/ - Unsupported modifier exception - Unsupported modifier exception - Can't salvage rule with only entity-based domain= option: isohunt.*|isohunters.*|isohunthydra.*|isohunting.*|isohunts.*|isohuntx.*|isohuntz.*|myisohunt.* - Can't salvage rule with only entity-based domain= option: torrentproject2.* - Unsupported regex-based removeParam: /^(?:correlator|f[cr-w]|p[e-sv]|[abdeg-or-x])/ - Unsupported regex-based removeParam: /^(?:correlator|f[cr-w]|p[e-sv]|u_|ga_|url|dt|adk)/ - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Can't salvage rule with only entity-based domain= option: the-voice-of-germany.* - Can't salvage rule with only entity-based domain= option: discoveryplus.* - Can't salvage rule with only entity-based domain= option: pobre.* - Unsupported modifier exception - Can't salvage rule with only entity-based domain= option: bigkickass.*|kat.*|kat2.*|katbay.*|katfreak.*|kathydra.*|katkickass.*|katkickass.*|kattracker.*|kick4ss.*|kickass-usa.*|kickass.*|kickass2.*|kickassaustralia.*|kickassbay.*|kickassdb.*|kickassfull.*|kickassgo.*|kickasshydra.*|kickassindia.*|kickasskat.*|kickassminds.*|kickassmovies.*|kickasspk.*|kickasst.*|kickasstorrents2.*|kickasstracker.*|kickasstrusty.*|kickassuk.*|kickassunlocked.*|kickassz.*|kkat.*|kkickass.*|thekat.*|thekickass.*|topkickass.*|torrentkat.*|torrentskickass.* - Can't salvage rule with only entity-based domain= option: isohunt.*|isohunters.*|isohunthydra.*|isohunting.*|isohunts.*|isohuntx.*|isohuntz.*|myisohunt.* - Can't salvage rule with only entity-based domain= option: torrentproject2.* - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported regex-based removeParam: /^(?!offer_id=).*/ - Unsupported modifier exception - Can't salvage rule with only entity-based domain= option: empire-stream.*|empire-streaming.* - Unsupported modifier exception - Unsupported modifier exception - Can't salvage rule with only entity-based domain= option: empire-stream.*|empire-streaming.* - Unsupported modifier exception - regexFilter is not RE2-compatible: ^https?:\/\/(?:[a-z]{2}\.)?[0-9a-z]{5,16}\.[a-z]{3,7}\/[a-z](?=[a-z]{0,25}[0-9A-Z])[0-9a-zA-Z]{3,26}\/\d{4,5}(?:\?[_v]=\d+)?$ -CSS-generic: 15682 plain CSS selectors -CSS-generic-high: 553 plain CSS selectors -CSS-specific: 9630 distinct filters - Combined into 9055 distinct hostnames - Combined into 491 distinct entities -CSS-declarative: 421 distinct filters - Combined into 622 distinct hostnames - Combined into 51 distinct entities -Procedural-related distinct filters: 866 distinct combined selectors - Combined into 1381 distinct hostnames - Combined into 201 distinct entities -============================ -Listset for 'alb-0': - Fetching remote https://raw.githubusercontent.com/AnXh3L0/blocklist/master/albanian-easylist-addition/Albania.txt -Input filter count: 34 - Accepted filter count: 31 - Rejected filter count: 0 -Output rule count: 28 - Plain good: 25 - - Maybe good (regexes): 0 - redirect=: 0 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 3 - Can't salvage rule with only entity-based domain= option: filma24.* - Can't salvage rule with only entity-based domain= option: www.filma24.* - Can't salvage rule with only entity-based domain= option: filma24.* -CSS-generic: 6 plain CSS selectors -CSS-specific: 239 distinct filters - Combined into 104 distinct hostnames - Combined into 1 distinct entities -CSS-declarative: 3 distinct filters - Combined into 2 distinct hostnames - Combined into 1 distinct entities -Procedural-related distinct filters: 4 distinct combined selectors - Combined into 4 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'bgr-0': - Fetching remote https://stanev.org/abp/adblock_bg.txt -Input filter count: 661 - Accepted filter count: 661 - Rejected filter count: 0 -Output rule count: 650 - Plain good: 650 - - Maybe good (regexes): 0 - redirect=: 0 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 0 - -CSS-generic: 4 plain CSS selectors -CSS-specific: 350 distinct filters - Combined into 175 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'chn-0': - Fetching remote https://filters.adtidy.org/extension/ublock/filters/224.txt -Input filter count: 15280 - Accepted filter count: 15215 - Rejected filter count: 1 -Output rule count: 6478 - Pruning requestDomains: from 6276 to 6268 - Pruning requestDomains: from 520 to 518 - Plain good: 6413 - - Maybe good (regexes): 11 - redirect=: 41 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 8 - Unsupported: 5 - regexFilter is not RE2-compatible: ^(?!.*(sharecast.ws|bunnycdn.ru|bootstrapcdn.com|cdn.ampproject.org|cloudflare.com|cdn.staticfile.org|disqus.com|disquscdn.com|dmca.com|ebacdn.com|facebook.net|fastlylb.net|fbcdn.net|fluidplayer.com|fontawesome.com|github.io|google.com|googleapis.com|googletagmanager.com|gstatic.com|jquery.com|jsdelivr.net|jwpcdn.com|jwplatform.com|polyfill.io|recaptcha.net|shrink.pe|twitter.com|ulogin.ru|unpkg.com|userapi.com|vidazoo.com|vk.com|yandex.|yastatic.net|ytimg.com|zencdn.net|player|youtube.com|cackle.me|googleoptimize.com|vuukle.com|chatango.com|twimg.com|google-analytics.com|hcaptcha.com|raincaptcha.com|media-imdb.com|blogger.com|hwcdn.net|instagram.com|wp.com|imgsmail.ru)).*$ - Unsupported modifier exception - Unsupported modifier exception - Invalid network filter in chn-0: @@||ad.alimama.com^$genericblock - Invalid network filter in chn-0: @@||cmechina.net^$genericblock -CSS-generic: 754 plain CSS selectors -CSS-generic-high: 403 plain CSS selectors -CSS-specific: 6507 distinct filters - Combined into 2795 distinct hostnames - Combined into 1 distinct entities -CSS-declarative: 77 distinct filters - Combined into 70 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 92 distinct combined selectors - Combined into 65 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'cze-0': - Fetching remote https://raw.githubusercontent.com/tomasko126/easylistczechandslovak/master/filters.txt - Fetching remote https://raw.githubusercontent.com/tomasko126/easylistczechandslovak/master/filters_ublock.txt -Input filter count: 228 - Accepted filter count: 228 - Rejected filter count: 0 -Output rule count: 120 - Plain good: 115 - - Maybe good (regexes): 0 - redirect=: 4 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 1 - Unsupported: 0 - -CSS-generic: 36 plain CSS selectors -CSS-generic-high: 4 plain CSS selectors -CSS-specific: 231 distinct filters - Combined into 167 distinct hostnames - Combined into 0 distinct entities -CSS-declarative: 8 distinct filters - Combined into 11 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 7 distinct combined selectors - Combined into 7 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'deu-0': - Fetching remote https://easylist.to/easylistgermany/easylistgermany.txt -Input filter count: 2340 - Accepted filter count: 2340 - Rejected filter count: 0 -Output rule count: 1783 - Plain good: 1777 - - Maybe good (regexes): 4 - redirect=: 0 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 2 - Unpatchable redirect filter: abp-resource:blank-mp4 - Invalid network filter in deu-0: @@||gofeminin.de^$genericblock -CSS-generic: 356 plain CSS selectors -CSS-generic-high: 34 plain CSS selectors -CSS-specific: 2398 distinct filters - Combined into 1772 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 84 distinct combined selectors - Combined into 60 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'fin-0': - Fetching remote https://raw.githubusercontent.com/finnish-easylist-addition/finnish-easylist-addition/gh-pages/Finland_adb.txt - Fetching remote https://raw.githubusercontent.com/finnish-easylist-addition/finnish-easylist-addition/gh-pages/Finland_adb_uBO_extras.txt -Input filter count: 177 - Accepted filter count: 177 - Rejected filter count: 0 -Output rule count: 157 - Plain good: 149 - - Maybe good (regexes): 3 - redirect=: 4 - removeparams= (accepted/discarded): 1/0 - modifyHeaders=: 0 - Unsupported: 0 - -CSS-generic: 53 plain CSS selectors -CSS-generic-high: 14 plain CSS selectors -CSS-specific: 1019 distinct filters - Combined into 556 distinct hostnames - Combined into 0 distinct entities -CSS-declarative: 24 distinct filters - Combined into 16 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 149 distinct combined selectors - Combined into 114 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'fra-0': - Fetching remote https://filters.adtidy.org/extension/ublock/filters/16.txt -Input filter count: 18886 - Accepted filter count: 18813 - Rejected filter count: 58 -Output rule count: 6567 - Pruning requestDomains: from 7820 to 7809 - Plain good: 6514 - Salvaged rule by ignoring 2 entity-based domain= option: gentside.*|ohmymag.*|maxisciences.com - Salvaged rule by ignoring 2 entity-based domain= option: gentside.*|ohmymag.*|maxisciences.com - Maybe good (regexes): 7 - redirect=: 32 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 5 - Unsupported: 9 - regexFilter is not RE2-compatible: ^https?:\/\/vitamiiin\.com\/(?!wp-content|uploads|plugins|themes)(.*) - regexFilter is not RE2-compatible: ^(?!.*(sharecast.ws|bunnycdn.ru|bootstrapcdn.com|cdn.ampproject.org|cloudflare.com|cdn.staticfile.org|disqus.com|disquscdn.com|dmca.com|ebacdn.com|facebook.net|fastlylb.net|fbcdn.net|fluidplayer.com|fontawesome.com|github.io|google.com|googleapis.com|googletagmanager.com|gstatic.com|jquery.com|jsdelivr.net|jwpcdn.com|jwplatform.com|polyfill.io|recaptcha.net|shrink.pe|twitter.com|ulogin.ru|unpkg.com|userapi.com|vidazoo.com|vk.com|yandex.|yastatic.net|ytimg.com|zencdn.net|player|youtube.com|cackle.me|googleoptimize.com|vuukle.com|chatango.com|twimg.com|google-analytics.com|hcaptcha.com|raincaptcha.com|media-imdb.com|blogger.com|hwcdn.net|instagram.com|wp.com|imgsmail.ru)).*$ - Can't salvage rule with only entity-based domain= option: downdetector.* - Can't salvage rule with only entity-based domain= option: vidembed.* - Can't salvage rule with only entity-based domain= option: vidembed.* - Can't salvage rule with only entity-based domain= option: fmovies.* - Can't salvage rule with only entity-based domain= option: fmovies.* - Unsupported modifier exception - Unsupported modifier exception -CSS-generic: 2419 plain CSS selectors -CSS-generic-high: 522 plain CSS selectors -CSS-specific: 2218 distinct filters - Combined into 1693 distinct hostnames - Combined into 3 distinct entities -CSS-declarative: 42 distinct filters - Combined into 43 distinct hostnames - Combined into 1 distinct entities -Procedural-related distinct filters: 97 distinct combined selectors - Combined into 117 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'grc-0': - Fetching remote https://www.void.gr/kargig/void-gr-filters.txt -Input filter count: 451 - Accepted filter count: 451 - Rejected filter count: 0 -Output rule count: 416 - Plain good: 416 - - Maybe good (regexes): 0 - redirect=: 0 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 0 - -CSS-generic: 3 plain CSS selectors -CSS-generic-high: 5 plain CSS selectors -CSS-specific: 533 distinct filters - Combined into 162 distinct hostnames - Combined into 0 distinct entities -CSS-declarative: 5 distinct filters - Combined into 5 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 2 distinct combined selectors - Combined into 2 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'hrv-0': - Fetching remote https://raw.githubusercontent.com/DandelionSprout/adfilt/master/SerboCroatianList.txt -Input filter count: 53 - Accepted filter count: 53 - Rejected filter count: 0 -Output rule count: 44 - Plain good: 44 - - Maybe good (regexes): 0 - redirect=: 0 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 0 - -CSS-generic: 11 plain CSS selectors -CSS-specific: 249 distinct filters - Combined into 149 distinct hostnames - Combined into 0 distinct entities -CSS-declarative: 1 distinct filters - Combined into 1 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 2 distinct combined selectors - Combined into 2 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'hun-0': - Fetching remote https://raw.githubusercontent.com/hufilter/hufilter/master/hufilter-ublock.txt -Input filter count: 325 - Accepted filter count: 325 - Rejected filter count: 0 -Output rule count: 200 - Plain good: 197 - - Maybe good (regexes): 1 - redirect=: 2 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 0 - -CSS-generic: 60 plain CSS selectors -CSS-generic-high: 15 plain CSS selectors -CSS-specific: 1020 distinct filters - Combined into 469 distinct hostnames - Combined into 0 distinct entities -CSS-declarative: 23 distinct filters - Combined into 21 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 21 distinct combined selectors - Combined into 22 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'idn-0': - Fetching remote https://raw.githubusercontent.com/ABPindo/indonesianadblockrules/master/subscriptions/abpindo.txt -Input filter count: 4286 - Accepted filter count: 4283 - Rejected filter count: 0 -Output rule count: 3017 - Plain good: 3017 - - Maybe good (regexes): 0 - redirect=: 0 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 0 - -CSS-generic: 239 plain CSS selectors -CSS-generic-high: 3609 plain CSS selectors -CSS-specific: 847 distinct filters - Combined into 690 distinct hostnames - Combined into 12 distinct entities -CSS-declarative: 2 distinct filters - Combined into 2 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 1 distinct combined selectors - Combined into 1 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'ind-0': - Fetching remote https://easylist-downloads.adblockplus.org/indianlist.txt -Input filter count: 4882 - Accepted filter count: 4882 - Rejected filter count: 0 -Output rule count: 4836 - Plain good: 4836 - - Maybe good (regexes): 0 - redirect=: 0 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 0 - -CSS-specific: 3728 distinct filters - Combined into 4088 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 93 distinct combined selectors - Combined into 89 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'irn-0': - Fetching remote https://raw.githubusercontent.com/MasterKia/PersianBlocker/main/PersianBlocker.txt -Input filter count: 1103 - Accepted filter count: 1103 - Rejected filter count: 0 -Output rule count: 605 - Pruning requestDomains: from 215 to 210 - Plain good: 564 - - Maybe good (regexes): 0 - redirect=: 0 - removeparams= (accepted/discarded): 12/26 - modifyHeaders=: 1 - Unsupported: 28 - FilterStrictParty: Strict partyness strict3p not supported - FilterStrictParty: Strict partyness strict3p not supported - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^promo/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /promo/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /promo/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^itm_/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^utm_|tatoken/ -CSS-generic: 17 plain CSS selectors -CSS-specific: 742 distinct filters - Combined into 391 distinct hostnames - Combined into 0 distinct entities -CSS-declarative: 226 distinct filters - Combined into 53 distinct hostnames - Combined into 1 distinct entities -Procedural-related distinct filters: 163 distinct combined selectors - Combined into 119 distinct hostnames - Combined into 1 distinct entities -============================ -Listset for 'isl-0': - Fetching remote https://adblock.gardar.net/is.abp.txt -Input filter count: 68 - Accepted filter count: 68 - Rejected filter count: 0 -Output rule count: 68 - Plain good: 68 - - Maybe good (regexes): 0 - redirect=: 0 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 0 - -CSS-generic-high: 1 plain CSS selectors -CSS-specific: 121 distinct filters - Combined into 40 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'isr-0': - Fetching remote https://raw.githubusercontent.com/easylist/EasyListHebrew/master/EasyListHebrew.txt - Fetching remote https://raw.githubusercontent.com/easylist/EasyListHebrew/master/EasyListHebrew-uBO.txt -Input filter count: 703 - Accepted filter count: 702 - Rejected filter count: 1 -Output rule count: 274 - Plain good: 249 - - Maybe good (regexes): 4 - redirect=: 10 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 1 - Unsupported: 10 - regexFilter is not RE2-compatible: haaretz\.co\.il\/(?!.*\.(js)($|\?)).* - regexFilter is not RE2-compatible: ^(?![a-zA-Z0-9\-]+:\/+(api-mail|dal|dcx|isc|iscwne|6days|animals|astrology|b|buzzit|calendar|cars|celebs|e|elections|euro|fashion|finance|food|forums|fun|healthy|home|judaism|kids|mag|maps|milon|movies|mundial|nadlan|news|nick|olympics|search|sports|tags|tech|translate|travel|tv-guide|tv|usaelections|viva|vod|weather|www)\.walla\.co\.il\.?(\/|:|$))^[a-zA-Z0-9\-]+:\/+([a-zA-Z0-9\-]+\.)+walla\.co\.il\.?(\/|:|$) - regexFilter is not RE2-compatible: ^(?![a-zA-Z0-9\-]+:\/+www\.sheee\.co\.il\.?(\/|:|$))^[a-zA-Z0-9\-]+:\/+([a-zA-Z0-9\-]+\.)+sheee\.co\.il\.?(\/|:|$) - regexFilter is not RE2-compatible: ^(?![a-zA-Z0-9\-]+\:\/+([^\/\:\.]+\.)*((gov|idf|muni|ac|k12|net)\.il|(google|blogspot|phpbb|minifier|enable|nagich|nagishplus|nagishly|livedns|user-a|emap|23tv|glz|icast|ecast|mediacast|live1|siz|gif|meduzot|telesport|teleline|livegames|2net|weather2day|mekorotapp|e-vrit|fav|slash|rabbi|kaplanopensource|systematics|israelcoronamap|icdn|wcdn|wallanews|wallashops|wallatours|wallaart|wallaprint|hamal|sheee|globes|madlan|yad2|mipo|b144|bezeq|yes|fxp|nick|d|maariv|iol|dominos|magazineitsuv|doctors|mishpati|lawguide|arcdb|zebarur|wlcdn|linicom|erate)\.co\.il|(kan|kankids|makan|iba|oref|iaf|parks|imj|nli|bh|isoc|hebrew-academy|kineret|teva|zavit|ip6|profile)\.org\.il)\.?([\/\:]|$))^[a-zA-Z0-9\-]+\:\/+[^\/\:]+\.il\.?([\/\:]|$) - regexFilter is not RE2-compatible: ^(?![a-zA-Z0-9\-]+\:\/+([^\/\:\.]+\.)*(facebook|fbcdn|threads|dmcdn|slideshare|cloudfront|cloudflare|fastly|fastlylb|gammacdn|edgecastcdn|footprint|incapdns|cloudapp|brightcove|jsdelivr|akamai|akamaihd|akamaized|akamaiedge|akahost|ctedgecdn|2mdn|edgesuite|azurewebsites|azureedge|windows|hwcdn|zencdn|llnwd|llnwi|boltdns|msecnd|bitsngo|nocookie|datatables|docdroid|iframely|algolia|anvato|maphub|dwcdn|typekit|edgefonts|recaptcha|ampproject|viafoura|yastatic|yahoodns|behance|darksky|google|twitchcdn|ttvnw|jtvnw|dailyuploads|deviantart|8ch|b-cdn|vodgc|hlsplayer|streamlock|web-view|streamgates|cdnwz|playgorithm|vidiom|radwarecloud|f-static|chartbeat|doubleclick|advsnx|sc-static|artipbox)\.net\.?([\/\:]|$))^[a-zA-Z0-9\-]+\:\/+[^\/\:]+\.net\.?([\/\:]|$) - regexFilter is not RE2-compatible: ^(?![a-zA-Z0-9\-]+\:\/+([^\/\:\.]+\.)*(flowplayer|amara|h5p|d3js|ampproject|promisejs|backbonejs|angularjs|dojotoolkit|telegram|telegram-cdn|openstreetmap|wmflabs|wikimapia|wikimedia|wikipedia|w3|schema|archive|mozilla|documentcloud|w|mathjax|userway|pannellum|tmdb|muses|openweathermap|uploadimage|postimages|postimage|imgsafe|4chan|4channel|4cdn|olympic|pbs|pbskids|npr|ntp|gnu|creativecommons|eff|icann|iana|ietf|wikileaks|ourworldindata|cookielaw|google|cdn77|browser-update|consensu|wp-accessibility|covid19maps|coronaisrael)\.org\.?([\/\:]|$))^[a-zA-Z0-9\-]+\:\/+[^\/\:]+\.org\.?([\/\:]|$) - regexFilter is not RE2-compatible: ^(?![a-zA-Z0-9\-]+\:\/+([^\/\:\.]+\.)*(google|gstatic|googleapis|jquery|youtube|youtubekids|youtube-nocookie|ytimg|facebook|fbsbx|twitter|twimg|x|instagram|cdninstagram|pinterest|pinimg|tumblr|giphy|vimeo|vimeocdn|dailymotion|flickr|staticflickr|soundcloud|sndcdn|scribd|scribdassets|tiktok|tiktokcdn|ttwstatic|muscdn|ibytedtos|sharethis|addthis|addthisedge|addthiscdn|reddit|redditmedia|redditstatic|redditgifts|linkedin|licdn|fontawesome|image-maps|cloudflare|bootstrapcdn|unpkg|cdnjs|stackpathdns|stackpathcdn|maxcdn|maxcdn-edge|netdna-ssl|netdna-cdn|kxcdn|ssl-cdn|muicss|tinymce|createjs|github|githubusercontent|aspnetcdn|azure|amazonaws|awswaf|elasticbeanstalk|rackcdn|netlify|jwplayer|jwpcdn|jwpltx|jwpsrv|jwplatform|brightcove|brightcovecdn|flowplayer|foliovision|streamable|kaltura|streamtheworld|mixcloud|bandcamp|bcbits|spotify|omnystudio|omnycontent|iheart|spreaker|podbean|buzzsprout|simplecast|podtail|apple|nobexpartners|vocaroo|embedly|iframely|snapwidget|thinglink|infogram|highcharts|airtable|printfriendly|algolianet|gravatar|svgur|svgshare|imgur|imgflip|gifer|gfycat|tenor|disqus|disquscdn|disqusservice|oneall|oneallcdn|tapatalk|tapatalk-cdn|mapbox|maptiler|mapquest|arcgis|arcgisonline|esri|here|ted|tedcdn|kickstarter|riddle|strawpoll|9gag|9cache|unsplash|freepik|imageshack|tinypic|photobox|photobucket|imgbox|imagebam|gifyu|makeagif|reactiongifs|gifbin|gif-finder|pastebin|rawgit|rawgithub|knockoutjs|gridstackjs|ravenjs|liveleak|metacafe|mcstatic|ign|ignimgs|365scores|buzzfeed|digg|stumbleupon|mix|getpocket|blogspot|wordpress|wp|videopress|wptavern|livejournal|withgoogle|googlegroups|googleusercontent|googlevideo|ggpht|noembed|appspot|firebaseio|firebaseapp|libring|hcaptcha|paypal|paypalobjects|amazon|media-amazon|media-imdb|ebay|microsoft|live|bing|msn|yahoo|yimg|yahooapis|duckduckgo|yandex|webflow|rtlcss|dropbox|dropboxusercontent|dropboxstatic|dropbox-dns|timeanddate|momentjs|weather|accuweather|theweathernetwork|windy|sat24|rainviewer|uvlens|statcounter|adobe|onesignal|livefyre|pushwoosh|tinypass|addtoany|addthisevent|addevent|addtocalendar|sumo|sumome|chatango|bitly|tinyurl|ipcamlive|steamstatic|playstation|discord|discordapp|mixer|odysee|rumble|bitchute|parler|gab|slideplayer|kym-cdn|gyazo|icons8|iconfinder|iconarchive|iconscout|flaticon|kindpng|pngitem|prntscr|deviantart|firefoxusercontent|box|feedly|feedburner|phpbb|vk|userapi|whatsapp|vroptimal-3dx-assets|bbc|cnn|go|nytimes|nyt|today|gofundme|fifa|uefa|nba|turner|xkcd|mtvnservices|cc|tmz|bugsnag|zoro|hebcal|fontsproject|kayma|kayma-dashboards|kayma-insights|kampyle|vicomi|openweb|cincopa|avplayer|vidnt|peer5|h-cdn|bynetcdn|cdnwiz|best-tv|viewbix|streamrail|smv-cdn|cloudvideoplatform|dxmcdn|dxmdp|waze|hunchbots|jeeng|cloudinary|sphereup|poloriz|applicaster|cloudwm|cloudwm-waf|negishim|accessibe|accessibeapp|acsbap|vollotech|mk-sense|allyable|shortaudition|spaceil|clear-map|segmanta|opinionstage|playbuzz|apester|qmerce|outbrain|taboola|taboolasyndication|googleoptimize|google-analytics|googletagservices|googletagmanager|googleadservices|googlesyndication|cloudflareinsights|chartbeat|scorecardresearch|serving-sys|exposebox|dynamicyield|coralogix|browsiprod|ip-api|petametrics|cooladata|hotjar|pusher|carto|fortvision|fortcdn|getsentry|trackjs|gamezhero|nick|nickjr|teennick|travelriskmap|sinclairstoryline|fresnobee|nbcchicago|magazina-il|raxcdn|pagewiz|pas-rahav|aniview|adnxs|sekindo)\.com\.?([\/\:]|$))^[a-zA-Z0-9\-]+\:\/+[^\/\:]+\.com\.?([\/\:]|$) - regexFilter is not RE2-compatible: ^(?![a-zA-Z0-9\-]+\:\/+([^\/\:]+\.(il|com|net|org|gov|mil|edu|int|(ac|gov|nhs)\.uk|(google)|(google)\.(com?\.)?[a-zA-Z]{2,3})|[0-9\.]+|([^\/\:\.]+\.)*(omny\.fm|anchor\.fm|simplecast\.fm|castbox\.fm|github\.io|socket\.io|codepen\.io|polyfill\.io|embed\.ly|iframe\.ly|infogr\.am|t\.me|flourish\.studio|flourish\.rocks|uri\.sh|po\.st|plyr\.io|piano\.io|tg\.dev|periscope\.tv|pscp\.tv|vine\.co|popkey\.co|tenor\.co|redd\.it|ibb\.co|vgy\.me|postimg\.cc|imageshack\.us|prnt\.sc|imagesup\.co|weserv\.nl|telesco\.pe|powr\.io|pippa\.io|last\.fm|scdn\.co|adobe\.io|viafoura\.co|lmao\.ninja|disease\.sh|web\.app|twitch\.tv|rmbl\.ws|stories\.sc|vid\.me|spot\.im|spots\.im|inthegame\.io|cybercdn\.live|h-cdn\.co|minute\.ly|vttp\.co|tldw\.me|feeder\.co|del\.icio\.us|telegram\.me|yandex\.ru|dailymail\.co\.uk|dailystar\.co\.uk|bbc\.net\.uk|bbc\.co\.uk|cnn\.io|bit\.ly|goo\.gl|g\.co|youtu\.be|t\.co|fb\.me|m\.me|instagr\.am|wa\.me|amzn\.to|wp\.me|git\.io|docdro\.id|arcg\.is|ow\.ly|disq\.us|discord\.gg|tiny\.cc|ex\.co|jogo\.studio|nagishly\.co|user1st\.info|knesset\.tv|knesset\.live|walla\.cloud|103\.fm|nickjr\.tv|amagi\.tv|logidea\.info|zoomanalytics\.co|firstimpression\.io|rtk\.io|trb\.tv|ren\.tv|atom-data\.io|sentry\.io|outbid\.io))\.?([\/\:]|$))^[^\/\:\.]+\:\/+[^\/\:\.] - regexFilter is not RE2-compatible: ^(?![a-zA-Z0-9\-]+:\/+www\.(walla(news|shops|tours|art|print)|hamal|sheee)\.co\.il\.?(\/|:|$))^[a-zA-Z0-9\-]+:\/+([a-zA-Z0-9\-]+\.)+(walla(news|shops|tours|art|print)|hamal|sheee)\.co\.il\.?(\/|:|$) - regexFilter is not RE2-compatible: ^(?![a-zA-Z0-9\-]+:\/+(www\.(walla(news|shops|tours|art|print)|hamal)|(api-mail|dal|dcx|isc|iscwne|www)\.walla)\.co\.il\.?(\/|:|$))^[a-zA-Z0-9\-]+:\/+([a-zA-Z0-9\-]+\.)+(walla(news|shops|tours|art|print)?|hamal)\.co\.il\.?(\/|:|$) -CSS-generic: 5 plain CSS selectors -CSS-specific: 441 distinct filters - Combined into 320 distinct hostnames - Combined into 1 distinct entities -CSS-declarative: 5 distinct filters - Combined into 3 distinct hostnames - Combined into 1 distinct entities -Procedural-related distinct filters: 5 distinct combined selectors - Combined into 4 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'ita-0': - Fetching remote https://easylist-downloads.adblockplus.org/easylistitaly.txt -Input filter count: 3547 - Accepted filter count: 3545 - Rejected filter count: 0 -Output rule count: 3279 - Plain good: 3275 - - Maybe good (regexes): 4 - redirect=: 0 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 0 - -CSS-generic: 363 plain CSS selectors -CSS-generic-high: 53 plain CSS selectors -CSS-specific: 2980 distinct filters - Combined into 3211 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 26 distinct combined selectors - Combined into 26 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'jpn-1': - Fetching remote https://filters.adtidy.org/extension/ublock/filters/7.txt -Input filter count: 1891 - Accepted filter count: 1891 - Rejected filter count: 0 -Output rule count: 1311 - Plain good: 1267 - - Maybe good (regexes): 16 - redirect=: 23 - removeparams= (accepted/discarded): 0/1 - modifyHeaders=: 0 - Unsupported: 5 - regexFilter is not RE2-compatible: \/kyodopress_cms\/wp-content\/(themes\/kyodopress\/img_banner\/(?!bn_newspaper\.gif)|banners).* - regexFilter is not RE2-compatible: ^https:\/\/(?!www)[a-z]{3,}\.[a-z]{8,}\.com\/index\.php\?main_page=product_info(&stl=\d)?&(?:cPath|products_id)= - regexFilter is not RE2-compatible: ^https?:\/\/(?!www)[a-z]{3,5}\.[0-9a-z]{4,10}\.[a-z]{2,6}\/[a-z]{3,15}\/(?=[a-z]{0,9}[0-9A-Z])[0-9A-z]{10}\.html$ - regexFilter is not RE2-compatible: ^(?!.*(sharecast.ws|bunnycdn.ru|bootstrapcdn.com|cdn.ampproject.org|cloudflare.com|cdn.staticfile.org|disqus.com|disquscdn.com|dmca.com|ebacdn.com|facebook.net|fastlylb.net|fbcdn.net|fluidplayer.com|fontawesome.com|github.io|google.com|googleapis.com|googletagmanager.com|gstatic.com|jquery.com|jsdelivr.net|jwpcdn.com|jwplatform.com|polyfill.io|recaptcha.net|shrink.pe|twitter.com|ulogin.ru|unpkg.com|userapi.com|vidazoo.com|vk.com|yandex.|yastatic.net|ytimg.com|zencdn.net|player|youtube.com|cackle.me|googleoptimize.com|vuukle.com|chatango.com|twimg.com|google-analytics.com|hcaptcha.com|raincaptcha.com|media-imdb.com|blogger.com|hwcdn.net|instagram.com|wp.com|imgsmail.ru)).*$ - Unsupported regex-based removeParam: /^(cookie|ga_|u_)/ -CSS-generic: 110 plain CSS selectors -CSS-generic-high: 10 plain CSS selectors -CSS-specific: 5991 distinct filters - Combined into 4055 distinct hostnames - Combined into 7 distinct entities -CSS-declarative: 174 distinct filters - Combined into 151 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 875 distinct combined selectors - Combined into 840 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'kor-1': - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filter-uBlockOrigin.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-share/3rd_domains.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-share/1st_domains.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-share/general_elemhide.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-uBO/specific_ELEMHIDE.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-share/general_url.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-uBO/general_url.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-share/specific_URL.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-share/specific_ELEMHIDE.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-share/allowlist.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-share/extended_css_ELEMHIDE.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-share/extended_css_INJECTION.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-uBO/specific_REDIRECT.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-uBO/extended_css_ELEMHIDE.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-uBO/extended_css_INJECTION.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-uBO/scriptlets.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-share/javascript.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-uBO/javascript.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-uBO/antiadblock.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-share/removeparam.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-uBO/allowlist.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-share/specific_CSS.txt - Fetching remote https://cdn.jsdelivr.net/gh/List-KR/List-KR@master/filters-uBO/specific_CSS.txt -Input filter count: 1253 - Accepted filter count: 1247 - Rejected filter count: 0 -Output rule count: 896 - Pruning requestDomains: from 297 to 292 - Plain good: 728 - - Maybe good (regexes): 134 - redirect=: 21 - removeparams= (accepted/discarded): 1/0 - modifyHeaders=: 0 - Unsupported: 12 - regexFilter is not RE2-compatible: ^https:\/\/nstatic\.dcinside\.com\/dc\/event\/nft_gaejugi\/(?!nftcon) - regexFilter is not RE2-compatible: ^https?:\/\/img\.kidkids\.net\/banner\/upimage\/[A-Z]+(_|-)[A-Z0-9]+(_|-)(?!LOGO) - regexFilter is not RE2-compatible: ^https:\/\/image\.aladin\.co\.kr\/img\/banner\/flash\/welcome\/nav\/(?!181010)[0-9]+_tab - regexFilter is not RE2-compatible: ^https:\/\/static\.wixstatic\.com\/media\/[0-9a-z]{6}_[a-z0-9]{32}~(?!.+doc).+ - regexFilter is not RE2-compatible: ^https:\/\/thumb\.toomics\.com\/upload\/banner\/(?!main|cut) - Can't salvage rule with only entity-based domain= option: xn--h10b90b998c.* - Can't salvage rule with only entity-based domain= option: newtoki.* - regexFilter is not RE2-compatible: ^https:\/\/(www\.)?filetender\.com\/images\/(?!logo).+\.(jpg|png)$ - regexFilter is not RE2-compatible: ^https:\/\/(www\.)?ruru\.tv\/uploads\/[0-9]+\/((?!16682220461360)[0-9]+) - regexFilter is not RE2-compatible: ^https:\/\/today-sports\.io\/img\/.*(?=(evolution|banner|\.gif)) - regexFilter is not RE2-compatible: ^https:\/\/s[0-9]+\.sonagitv\.[a-z]+\/sonagi[0-9]*_media\/sites\/[0-9]+\/[0-9]+\/[0-9]+\/(?!(SSNGINDSALC|cropped|sonagitvlogo))[a-z0-9-]+\., Can't salvage rule with only entity-based domain= option: sonagitv.* - Unpatchable redirect filter: google-ima3.js -CSS-generic: 12 plain CSS selectors -CSS-generic-high: 67 plain CSS selectors -CSS-specific: 1194 distinct filters - Combined into 1308 distinct hostnames - Combined into 2 distinct entities -CSS-declarative: 170 distinct filters - Combined into 153 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 102 distinct combined selectors - Combined into 150 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'ltu-0': - Fetching remote https://raw.githubusercontent.com/EasyList-Lithuania/easylist_lithuania/master/easylistlithuania.txt -Input filter count: 568 - Accepted filter count: 568 - Rejected filter count: 0 -Output rule count: 523 - Plain good: 520 - - Maybe good (regexes): 1 - redirect=: 2 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 0 - -CSS-generic: 5 plain CSS selectors -CSS-generic-high: 5 plain CSS selectors -CSS-specific: 564 distinct filters - Combined into 320 distinct hostnames - Combined into 0 distinct entities -CSS-declarative: 7 distinct filters - Combined into 7 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 7 distinct combined selectors - Combined into 8 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'lva-0': - Fetching remote https://raw.githubusercontent.com/Latvian-List/adblock-latvian/master/lists/latvian-list.txt -Input filter count: 185 - Accepted filter count: 185 - Rejected filter count: 0 -Output rule count: 144 - Plain good: 144 - - Maybe good (regexes): 0 - redirect=: 0 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 0 - -CSS-generic-high: 2 plain CSS selectors -CSS-specific: 184 distinct filters - Combined into 62 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'mkd-0': - Fetching remote https://raw.githubusercontent.com/DeepSpaceHarbor/Macedonian-adBlock-Filters/master/Filters -Input filter count: 289 - Accepted filter count: 289 - Rejected filter count: 0 -Output rule count: 158 - Plain good: 157 - - Maybe good (regexes): 0 - redirect=: 0 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 1 - Invalid network filter in mkd-0: data:image/jpg;base64,/9j/4gIcSUNDX1BST0ZJTEUAAQEAAAIMbGNtcwIQAABtbnRyUkdCIFhZWiAH3AABABkAAwApADlhY3NwQVBQTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWxjbXMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApkZXNjAAAA/AAAAF5jcHJ0AAABXAAAAAt3dHB0AAABaAAAABRia3B0AAABfAAAABRyWFlaAAABkAAAABRnWFlaAAABpAAAABRiWFlaAAABuAAAABRyVFJDAAABzAAAAEBnVFJDAAABzAAAAEBiVFJDAAABzAAAAEBkZXNjAAAAAAAAAANjMgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0ZXh0AAAAAEZCAABYWVogAAAAAAAA9tYAAQAAAADTLVhZWiAAAAAAAAADFgAAAzMAAAKkWFlaIAAAAAAAAG+iAAA49QAAA5BYWVogAAAAAAAAYpkAALeFAAAY2lhZWiAAAAAAAAAkoAAAD4QAALbPY3VydgAAAAAAAAAaAAAAywHJA2MFkghrC/YQPxVRGzQh8SmQMhg7kkYFUXdd7WtwegWJsZp8rGm/fdPD6TD////gABBKRklGAAEBAABIAEgAAP/bAEMABwcHBwcHDAcHDBEMDAwRFxEREREXHhcXFxcXHiQeHh4eHh4kJCQkJCQkJCsrKysrKzIyMjIyODg4ODg4ODg4OP/bAEMBCQkJDg0OGQ0NGTsoISg7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O//CABEIAFoC2AMBIgACEQEDEQH/xAAbAAACAwEBAQAAAAAAAAAAAAAEBQACAwYBB//EABkBAQEBAQEBAAAAAAAAAAAAAAABAgMEBf/aAAwDAQACEAMQAAAB5TDDbPbKFXMN/aJeC4hQ0tnVGgZ+ufmeuEUl91F208swzhkoVi1yGV2lyL7gTFZbRcPPLrj74xVfm/siPRnsi/uUh/m0cN4mzpF61ns5K40liqrfyVR48NxUXUHecNcko6xX2yl8c02T+N6ivxl7Sar1KrPZA91iwRtVw3DtaWJLJfYEuB4Uu1LkXwgtffML0roC+k3MLNNMaXXZaQus9AVcM7yjmxOxWbnMwybhPuQvPZmGe64WZeMj+3hlTauNwrDffKY7+A9S/FE2G2mqlrWNz6uOAQ+08BNa+l8tKnnsrL60VNreW8kuZatoZWt5xuQG7TrEk6VlqcR50DI5I3rcedReuhs1UP0A+nN4dePucxLQrLelJeGPTc70q8yZh5NPIIXvn5PaFhLZ3WlCNECyZRK2kiSQkzzCHXNdhnSnrFeGK3CHcY0lZkj6y5R68+Y1KB2USTrmmusxrxsp+iIXzvLUsjNX0UqzQ/BcNHnjPJMVzKTDTqkVqVqw8jkD79Ccqzc0pAd0KROer0SOXLzaVjUiso7UFkcj7aWV2z1hh575wq9mBr1nQW5/3N6P3nczqAuZy3OtEVHQyac5TFbL1IXXN5W9eT30rLeJ50/MdOvNZE5mbxRvTSSFbSE8rmb+C5hmQ+izMm4LrrZCOo5Bhz30My3zclp+9mY2WsSXGl851zz/AFzSWnSW8y0x0v8AVvlRbFMZVbdXxI52gHLXO6K4TJGznivE+hC8TF7g351EctuRPjqcudidFrzOQ4U6YFqDbG/g7K1a953qE5HrkjDjwWtShuWaHpj89JYMpnQhZdzVkn130zYZX5YwYKvFJUF+dax5sg+zB34r5c8tsB+vYlnZVjkr6Lnem9nqQVKxuh8r+ZFka41nm1rSqzaigaMPEDjMNcQ2oYLGV6BZV2hiZXXz9KbCUDBIrD1xK/c0WM8t5Dmk3nC+Queh2APikD6bQNqTmWyH8Zp4VFxtpnLPfLMzz3GrOkTa5KklgQR9Y3C1oEkCF0BcgCSzteUJcOkoYXaV4aXYNNRAF1fm3P2fSE1nNITQ+m4i8ezZd6wmcAVaeCYtkTnaYPpMFQ5vp0yg60TSlo5VAau+Wa+P54jUYNEpi7N+X3DwRLK6IQejJjznoWUmXnQu+eLRvMdeWxsSZz3xgfX8l1y0JO5vJ72fzzrOmONgU3E+kIx1pvp6tRxas2tY5M9fYZZb4GVr+zVJoNc53tsZ742G3nvmucz0gpYLWwsaLCglWYPIxHJlq71hIoWP1OLm2vT5nelbZzenPjKPbxF0yt6uWuZ6xLFAH2+V08KMV/ect7YlCfM9AXNMlv0eEpPe/OtpElbeGVNamNdqAmG1F9cpmKlSQHyNi5038ReSOTdC9Mqc5m5KETlvsM02+aapIVagvY8h9JTlz0hnTCWZTb//xAAtEAACAgECBAYCAgMBAQAAAAABAgADBBESBRATIRQVICIxMjM0JTAjNUFCJP/aAAgBAQABBQLUCdSasZtgWacy4ENhi6s2gmkbtNTPdNGgEOk26zZpBpNgmyaCaTQza07z3CbjNGMO4Tc0G4z3yquyx9NABqcu7pJpNJpNJoJtE2rNqynDe+JwupVy8dsZ97CdUTqLN6zVZ7ZtE7zXSK24cmXSKFPNxFPaOsRoy7Yra8nGhQ6rprPiaGaTSCqxp4e2eGsnhbJ4a2Gq1Zq0YvFXcdDAs28ywENk9xmybYn25PE5mDv6B8QRdNbIn1X7PO2mLQ1zN5Yp6nC4H4WD1eGSm/h9c8dhwZ+GJZk8Otbq8MnV4ZOrwydXhk6vDJ1eGRTw1pW3Dqz5jizzHFmTlYFrdThc38KmvCZ/Ez+JmnCJ/EwVcOul1VlFiOVIIPI953U+8z3ibtZ3Ug68iNrDuDXNzie5oo2jkqliErWBmJLWJFS154a8RkuEKXKFuldmrZK6WFNJt05FgIbJqzQVwKBNJpyTmw1m0zaYDpG+F+eR+V+IARAWjaGDcIo7t3g+v4+G+gdhHOi+kKTFrA5loXjNu/py/wDJi6SptvqcRfcCrCdRp7nIGg9QXp0U1vdMe1KFtyN7WWNbOrY7oTTYL1YWnGybLErrOWParw2CbmMCGBBK6nsLI1Z9C+onv/4U6GE6QDUw/wBFn+r5j55WHvj0JYhxK1uHC6urXi1rUuHhlGwUpTwZNi0Ju8Ovjhh1a4uDXamQle67DRcf13focq315k6TqTu0Uaf0bhN81ZpaN1SFnDJZWwfqAeCC0U1bbKcYS3YahjViJT02yGmpmybRyxMVsmwXYmI3Eba7OVeHk2qcTJ3+XZcXDyN74eRWsGHlGHHyFsOBmmJiXG04OUAUlWHl2Lbi5FUTh+To1NqP4DLhRlPeaTQzSaTSWD+L5p9uT/amyhFOat0ys3rB8yq2DMqRfH6q+aOqc+qyDL/+5LWtl2Uq5gzlRrMunw/ru/QJ5D2lW3DloPVqJvm8zuZtm2UL/kDRBeLLEYHdSHsxbGNdmRWHssumrSquugM26Wtub0VsMDAJLHlxInxDMX4dh0qTW1uZRj492OkHD72i6Y58BcTiI6HExsmvIt/LfVbfRserDzMbItyPx2vi5fV4j+36rf8AWc0+3LaSQoHoLqIbNZ3MWowADnd3m2aTT1XfoactIjbT6Nwm+bzNSZpNs2zSdudFzGAzqs0sK6e7a2HvZa664X1jGN2h7mbub9PKx7FVbOWRV4x7dldGdeqjH0sw8erwhngbpemqDBt1yCMrMpreix7ld6aLnTIYU4q4uTpl2BmGNkzOyFsyupOrOtOpN5huMck8L7yorjo1JW+zINVniLpRda0S+13tyLlscm3HRkoF4auzB/LXjpSKbDZb4i6HQ2PfkbrbbGKFaFurNVmZ3spVaYmTkhsnJvS7K714yjHlv5LP0Ns051PC6ib5ry0m2aehmgQz3LA+so+fjkCJ2heEpGO2b0Z3Os01m3npK7rKuWoENkLE8gDNWhsM6jzVvSPnZNk2TZPZNoj+2LXvhp0itt5Ed7P9XjV9W263Fseza8vpPU2kTG+afy3ZISyux8qy2zGtfJVbkxO1m5MiUK1dxyZXebcmy7K31Lbfdf1Lbb1NtDhaziEvcPccv9jpqUqtNuXb+V/0IZ8zSJgZViWYWTUV4dmyvEvtlmLdSHqeo2UW0iqmy4vh5SLXjZdwsqsqL41y1qjmpandPLslhRTkJeEZlVGK6z2maLGv1YhQOmu/tq9bJy0HPqCGw8tIFm2M4EJJmk09WsXuOVj8kOq2fav6yxdDUY40Zu/C1dkhm5tFtsSNbYwDFYSRPc5TcnIMwVWZZ8Q5Nk11gbafGXzxeRPFZE8TkRrbLAhNcU6S3UubbCikqfmP+gZprzzf1qqPEYdHl6ZVn4cXvjWVL1syxrsbA0KYNeMrZiUa2Gu6sutttArGAgoGJbTiY7DTrU/Sof4QIyTKscTHNkNFrywrXMGxRabFEt0FhYCG2dzy0gWaQuohZmgSbZpz05kzSVfXl0u9olRlo91R7Rhqq/LrrMa2vZ5XlGeVZ88uzZ5dmwcO4hr5bmTy3NnluZPLc2eW5s8tzIeHZ8PC+ITyriE8p4hPKc6DhOfPKc+eVZ88qz4vCs2eW5s8tzY3C84zyrPnlWfBwy9ZkWrYfRbebUrzbKq/H1h6skeEOb1a78uy9GuL1U39GDPCTx42rxFUdeI1hsjL69VWQaq/HLZEymaxckCdb28smrrU4t3Qse6vSyzqtj66uWK3MzWTSBYFnYQ2TUmBdYEmnI9p8+j5gWaSpvdzYahToXGoU6GH4HzGTWbHEFbGKNsSt7JXiBeemsY1Ui7iJj22WFEMeuVvpLNuqnRCBzooa9toUGWvsXnp69IeSkqQdRydYqazasKCfUlQ09yyohaQ6GBxAw01m6XVVOejUDVw+tldRj5D6GN9oObchB6G9Dc2ifb0f9Hx/wCq/iz61/b04f4vRl/ms+tf2s+f+WfZfnmJi/gMMyvtyH9B+OQlXrf7J9ZR+GwDVCYORjxPkS78zfSf/8QAIxEAAgEEAgIDAQEAAAAAAAAAAAERAhASICEwAzEyQVEiQv/aAAgBAwEBPwHTEqF7GyR8EztJIqkOsnSUSSSZE6vaCCEQRpJJIxcGQ2PnVD0es6oi62QtPraet3m0bSST10si8Du7QQQQQR0eTl4lLyayPJRTjwVUpVcIj/I3l4x+nPsqp+4KXipKf55/T5UmCyPlTBT66ETtVutH0QmKleiEcHA4dsKfwwQkhwR0xeLO09S6UJWrq1oUiR5Hz0ySMRN0O3//xAAoEQACAgECBQQCAwAAAAAAAAAAAQIREhAhAyAwMVETIkBBBDIjQmH/2gAIAQIBAT8B5LEMoo7lFctFHFhKTOHwHe+tD2JZsgnW5RRiV0rMzMzZmxSt81a10FyR7aWOzEUCutIZ2EIXf4b0yoyLZXkczIj2604/ZYv8LSLIfC4m7xM0/wBiUI0Yq9ken/Vkp/xk3a37j4f3RGKjuyPt38jeUBRi5dj9o4i0svneq30j8KjAwoW2mJ6a+9PTj4MI+CXggitWug9U9juV8PiSxjaJTcnvpwOEnuyuTjSxVos/HXtvqSGtENkXp//EAEAQAAECBAEHCQUGBgMBAAAAAAEAAgMREiExEBMiMkFRoQQgMDNDYXGBohRAQpGxI2JygoPCJFJzwdHxU2Ph8P/aAAgBAQAGPwJW6Cyvz78yWXFY5cVisViscmKxQbNSGSlusVj0Gg22/YtMknuQDXTmrhX6eeWYVJUx0Wi0rBbFiFsWqVINPQ29yusOdJvmdyk50R/e2Ul23pXbeldt6VU0RfOSwicFg/gq3Z3gu29K7b0rtuC7b0rtvSu29KtnvSp0xHeMlg7gsH8EDEES26S7b0rtvSu29K7b0rt/Su39K7f0qmFEfDd/2SlwRhRMRkmOdI87RyyyyCvdShD5KTgQrNKmRJWupuYVitJdymOZbJf3ayvkkU4j44lJ8Je+cmiu1iC35HJLnyKsr5Jc+raUcZBUUyVIEhvVUNwmEGPMvH/6SrdEqEpYqp3yV9m5HNPmhLEKRVuZTDaT4Kl4kfev1v29BN0KK6+LMPookOiLEpOLP9IhznNbJtM8Zu2J0XlNVnUSbvTYgLgH6Iq2FCJHJA2+PcoVDXUPDST4otzcR0nSm3/S9lJtf6L2Z7jnyCZDAdxTXRiQXkhsu4JkOK37TCiHsH9ynR2tiMLSBJ/Qcl/P9csvcJBUtC/hdXcVU6/mg8Msq41DnFFzGSB2IvLQ071OMyY+6tD1f+LORMdnOlg0YlezMxQE5vG7AeeSpjLLN0aSu3iEYdFwq3NsMkwziEIJZpOwWpxCzVOluU6FZVw22X2wlNTDMVm3N0lqcQqXCRHP/W/b0GnnJ/dMgnCK1zQXVaBkmNhgtDL33pzYjNFxqsdqDYcPV1Z796EOKKmy0v8AKhvbMCGGiXghnA8UkkUneV7XTvt5SUMxOtYRJ/8AlVtE2smBLvTIkVtT22q7k6BDrNRBm87ug5NP7/1yzCn7hdCHBcAHb1/EH/C+8djcVWRpYyX2MnjcqeUgBu5GE27RaoqxJPeprwtzQ/4nfUqp2Jy0bGgSC0r0xJD5I8oi6kO/mo0tYkHyUV8UaNBEsk6Me8LksONi2rirFvzUaBhELZBNcWkBP8SoJgioBsrb00RxKUXgjEYKmnArkudsZEXRfSZznNO8uf8Arft6ay0lbKOh5L+f6+6GexTatJ3BSYLnFyvFDvK6zhcQrX8cl8k+a3aHEJzW4A5faILm3FwTgmcja4Oe58zLAJvIuTnRZrHeU7k4cA6qd06JFc2VJ245MW/NQeS1AvE9q1mjzTsy4eM9yEWPEFLfvIuG0zWchuAB75IQHuqeXTsZrRc0fmULk7CHFokT3lCqI0D8Sc5lxzMFgsFM/wDN+3Ixju0xWZ75LMwbAWWsnVHBpTWuNiQnAHaq34gpjHdpijDR8FnI+OxqqOwWWsoTjtRlNaabDfjExRYdiaB/KFmPiIm5BpKc1rrBQj3JoOvE+id4rk35/rzZHJbpXZLrHJit6uQ1Ug8/7N0stuZiscmPSWyW5g/q/tQGzapvq8lD5S34TdF4E57VcJ/4Cm+IThS033JsMyDReQVTq/JNjN8CvIqT7P3qTty1W/JNmjInFAxsG70XyKbG+JtivaX7AJeKc920IeKcocR+qxqDzvTvFcm/P9ctsgiMZY4XCaHt1jIX2rU4hGhuripxGyCpeJIOiCVSlCE5IuosO8KuGy3yUookVni3QO1Z6WjOXmnPAs3FBzG2N8QjCe24Ez4KYvLFFzcArjLRB+a3neVWxU71cdHbop5ZDnTUsn639kaTKeSnYtElScVbapt2KeJVjjkp2FTbkscMkwtcrXK1ypF6DXGclo5CXbVmybKpuKmVyb8/1yXy8m/CoEGcpxCmBmdqrAGEsVyr+qo7ThIfNe0RdSGwfNQYjsSXfVcoEUyFN053J3lzqDYpjXRaJNEhKahcmhOrcDjJP5B8NNLfEJw5QS0Z3+yj5hxdhis3FrLpXlKSDm4ezbcVE/ConlkwRbs8FoT8gtL1ZDUMVpSkUdgnksr9HboZqakpqXNdyaPZj9u4r7KUQbwQur4hdXxC6viFeHxC1OIWpxC6viFqcQtTiFqcQrQ+IXV8Qur4hXh8Qur4hdXxC6viF1fELq+IUzD4hanELq+IXV8Qur4hdXxCnymUJu8lBkK0Ngk3mw4curEkxjB1bqlnPZ2VTnPvUeNEAcXPnSs3DYIY2gJsM2ATIX8k+KdohwcJSKOahNYTaYQbFY2JTgSg9kFoIVeYbPeixrQJuqKfClZ8uCnFhted6zlIkG0S7lIQxdFrWgTylox2KT8Dipgqr4Rgg5q0kX87R6aXS2V1ZaIU3mZ5lUQqUES7yrmZWkphSKsrqYy921UtwGTv6aynlmFfJbJMZGuKsebN2O9SF5rSwVDTbvwU5cUfdB7h583y6MZR056I+PRO8Mn/xAAnEAEAAgIBAwMFAQEBAAAAAAABABEhMUEQUWFxgfAgkaGx0cHxMP/aAAgBAQABPyF3GPajOd0X0gDr5Zi+yMPQUmDEt0T0dDF3RjAZg5VF7bfQR0HjFfMs5hnRC7oYzQgbY87EeJqXI1v0gCwBjp2Xa0+DvL909TKd2U6T2Z4p4ot94xGYJ7qCUhIvJHkEA0TpvcnnlrkjwsacwuvVQ7jrYs0wjUCtdKHyl1O3XrIIuCHi4eml5mSjRKVLYd8pNoPaHJT1SDc/dKv6xLVvRhlrehcXdN4mXdlRallz0acwA102zOzjzw7pQh6tCcmWdFRcFunEcPpFYY6lbwuW4MZoTRMJ1PWXhrMXUAZTADljt+OEflMVVC2EvHBxymI/8T+oD/j/AFHOW9sZ4YeGHhj44eOHhhpELL9xEqwGHj+p/wAr+oSiiib2IWbIKcQ9Mk6QKkevzVLH10g41IG8QHZfQAp6CukBEUgM9NRHW95zRppcR7r6NbNs7r/YnGr2y09ZDM3kd8RBSHe4hQt+ZVJ9oNVBtuag4TIjPjlKdNmzsuqGkiI4Srhy9UWJ5ol5iwrvNfXfNMdRCxJYykA1dSjVElNlDTHeEiLf0n6S1Rp6FEuGk6Yjv9GOmv1NlnqB5lW2o79PqqVElsuTPio6bV9PWjfUBs5lV4JlZo0lWKlV2f8AhdVQLsc+8qtcvPvKZjO0qg91NP2YgCzOWI7TGIx6VzKt15VFS6DV0mNLrP6iPZh+Ii05mtDKjc9RLAHwuXkdpKY9HUqc6+rMqUvnuUL0qXEomppO0Kx9D00fRGwd+hNXtDyNpghXk1lHbTlmW3EMHlJXGwqhoW2sZGClGnvjIw3qEJVtsEVBNIrrlmo2g0wK3Aiel03hJGVIZRZVmDcLFMIMMrk7lS7hxwQ7WlhgooHI9sH1vTaRlW+zrVvcewmaU/8AwT5j2kHcjCvtEwlerYU+sqmXzhCe8BVVtu69YU7ZWhVhmyMU4jW1NzFzBdNuDCbw7Az94fAU1NHmX57ssYHmASpWvI+XMFe1O/leYdRZ5h55dAFxaVD9zh6l5SqPN1Pk/wDsrlb3JX31EvdyI/p6U4ESz/vGsmlZmvOpgqB8+ZsAeFP51FS07I/gZzzZy96h+2InhmxPxKP3hB/LCLBaI1/B+Y3RgJKm0YXi5eIAlUqVBh1yUPGG3j/RD6gdBaqnGdTueCWoKGXY0tBK0pGxGbdefKZ83ALtu6dmA3lDuQDhWQJZnEFdlPLnKimPNVWXr+4QxGvA2/dmXGwGlRVPnzKF2QFrwolkuX0uXMymdUw4GIu43kiEZ6+D6ktsTwRXWJ3IKBgU8TNWN8x2aKhs9puteqx74Fg9hcpyDKJwTN6c7NRuwuGFl9jSaH+zKZcrXpHvbBLE4hXWyJDueuj7EepeRfMuVL2+M4DEDuaw8R3qN54ENz6cPC/aVGlQI2+3QIIrL4MCwGQugDWYs3beDHMXIeYT8OXww0R8mUKnRwG5ZBSafCMJqUaqpnSjPKqJXz20eu4Kp7fofRiO+mr6DR1WXRc8o9am5ZxoKUFiM4eIbQrosHQVh2H0bwZ6A702KWYz0B+lHmJ4jw4nIgmEglOoUbGpTjihUFptZO5F1VeQLF2nM7PPrHBaHrgPbU0vrNAt3Vyhdxwzq+OZiBwdorO/PTwlrCU8r2L396ubgAHpcMdBDDWAUTZracFZZ2EEe7DSpqqrKI1noUWV6dBi/wAOUcPs6Hi4AKbvWdijwGHeFH5na/acthAPhLVYgmb2YAFSjpHPGFNZcx6kOjkbxJwLoPeiX7RpuUe0t0QTRA8KlfZAvLz9LqWn6nrMXvfll1Xp6RXNsGtywrZGO8xBxGiBeG34gNZy9DqNLQ/iH72AMiz/AEncqU4J8gQBRZthSqBaxDGamrKld7k9Lqcgz8QO0MAKUo/wIhkLDRKWyeI1zNphX8pH5z99P+UaRI4lh9qbllmFO5UHCAkrqy0aiy9dEsHEB6lP2/7BVeoidx+ZZ4S74qAYSTuX0Si1D94O3ELjqjgWe1AE5IDxDumzK596qb3HYx0+/lXBNyqBd0W5l+1M/XFJSKWrvpMFbMbKILVxlTqFJZzOR0laumfQRvm60qjtNlUBbeGAqzMGYitA6AHxuZcGC3lBgyTAVH4J1pVSyrG7fiASsSAHYjg+sUHSKUccNvfR2gBqiqXoOR8IsAnWHUow9j+zNxAx7w9FqMNnkE/P/wAhyfj5eCcnuHifm/3BFSUrMVXZ0WYM6Q/bKYLqiK43BYfz/wDZudarIU+8HXjmxPxDdog98Sk30uLuTOQ/cRNsjSfph9jxVA/eD2tLPBMRQ2DLcWAq79r1Kd0AYMfeKAH5j3eY6CmXomSnYMaOolXVKpi+3mbMkDFxNcaYVu3CeauGq6BeelhuI6z6ROsRt3BMWAJhsormChNTx9DXW4qe76GqtyofaZTr6YjpnL9ZYdmKnxHLKin06AGHLZAKES1VO0ur1SvaFDU5RUvJlmfcUprtADUUF7hGLKdRQZlAH4RW0QGpJ2YCQ7cFyxTHAjAJslOpe7RMVuVwElOiD0ocxVbFz0Cvdi4pGfk/8l3UXXwC/wCQYDEFzf4jsO3+onLS0MI5n14E/SEsWTbYziUWuA0RVOVliu8cbU3Rhha/XTPokYLbBiZKAvSuYMYgcL8oMx4OxZVyoUVU/FxL73KuMp/Ca2PzMiuWMD+WZ781/gghxeI3XIw8kKarvZv2lVDMo8cTbsR1qLsSoN6ICaTLMJxEYEm3S1xBTqrghDunbpVwBmxNB9JnZo8ksXRcRUWUbNkuvgvjaY5Q4tc/djT8/wCZ8n9Inq3y7ztn8eZ8f9J8v9JXr4PWfP8A0ny/0h8p/s1Pn+sTlt8+8eH5/WHxP9x4/n9Zyfn9Z2vj9Z83958/94V4Xy3Pj/pPm/pEsYHy3Pg/vPg/vHLC7AvsEJxzFuu8oNRIkSNwBQ8wJgoHveK/MDMByPdDh42NGZbsr3L6sNE7Pl7xqgGz1XG5inYgZFbWXUzdRWxXrCzw6XmAwBbybuIHuO71UOwcp7WlELStxlcFQZ1FgaYO43CNLqVKJgty9UtLtQ7PeYWo83MC/wBT3jr2pdFXsEKt1qUwhWDMOcQ9Q77FgiUIk7kp2wQJUaDMb9PQwnuH0XJKFmXNke77wbLIqSzInQczD0RS8YIqHqu/UeKxwajGFlSiI9f5EjRfKiX1GhMySU5nhcas/WVDNirM/XSsaG0AwrB0Z/lg6rwQ5OerGJKjDrEZeYKp1s702pA4iOyCwF1MR+0WEzmHWSzkRSIvfBM8aiL2TcRnUuZZ6Pqg8i6ahm1WeqVaMlsOknE2+iIxm3Q11nTX651R2mzoaPq3+rq9CdR00hpATqjtho6bEAU89G8/A6OvrPUemk0/8Bq6EbJ4clfbEwWNqNmh8wA47TJX8zG+8/XT/9oADAMBAAIAAwAAABDyQ3TrhZvCnY4/ZzKL8UBLHQF09mNmqlJH2919OV0q9hsgDXBs08dNcSo+ZX1dACbN7nnO7Z7zg64gNNjz97/vhwJpoUKzpF7RJdS4aBkywyDy5ELpMGBZXhiE/wDZDjTXeWn+U43jRCMt6t9YRghOXjX7Ab4ny8DCJjUevaiN0THj+DSnxxCFihzxmQVsnN6fKRIQ+8bQH82JD78WwTNN8J8k5yeaGW7pYCM3d9NoCslpTkKGXsgcbwyj9ACS3QoExBJ/rjz5K3SmsWN+pXFM/8QAHxEBAQEAAwEBAQEBAQAAAAAAAQARECExQSBRYXHw/9oACAEDAQE/EMC0tguxDHLuCwcCW9ZLOHt1ZbblsNtmzEjzrhsMMBI3rl1d5hyTe9gzsh9t/J/cDgzIDeB67lv8Rh9jrPWWttQaJPWxxnLxyXrjIy2R8t/HZkSY3sE9l7/GR+2Ps49k6sn8sztxs7Zl/wAjBLvG2228bbDLrggTjAsLT5dXU+8M8Ny1/OWFvGHU9upO+4FgHc+ECGwRq6cNRrggW8bbbbs/I59hB/420iEmh/Jb2Ov5Ki+nt2qcEYyHQBl2Cf8AV8zwJMGfL0Phu3hwHO22beuA9y5w9Wt64yCzLeAS/JM4H4beMB2SYhAMAEo7AHSTD17H0J794n+ZGMzqC7+wQQPbzgbeSR21ZsHdqyGM9SuCbeFyG8nu7T5+Xk7CeQSihbv4FdwTI/RyLIXB9wltlux3dF4//8QAIhEBAQEAAgIBBQEBAAAAAAAAAQARECExQSAwUWFxkaHR/9oACAECAQE/EN5XLN2LoRoukE6WLLJLOQwHgka8CyyeBu6cLC9omOHSPidmWnhjrhxI9WvRdmcDYJZykgz3gwk2xAwYc7w3nzuwzggmrV9yMdHwXqFh+G/B5hF8Eb0bGWc76noyyyw4/dlnGWWWWWWSRx4sJAEthHqFAPEtu3Dqyyz6KMOvcuvSUdSnqPa/BbbbeNtu7u7sbGyCwX9WkPtevzdyBdU0tb6POFquu8xlRpMRgBiMgD7Q0J/L936kP9iJjx9ryjwbv/LxOGHzHRg3gMAnhlttvwWyOCzh592BUnXSSBgdTfTuRXcu+meY9DbDMvwL8T+QMwdSjuQDQ93jj2fQWHdoe7ctukDMuNnz88nJE8twHAsPAA64OFWNL3CY/U7lgWXVnEmQ3j//xAAnEAEAAgIBAwMEAwEAAAAAAAABABEhMUFRYXEQgZGhscHwINHh8f/aAAgBAQABPxAvEdoRi7uzC208GJdvnoSkUHWs2lrOKKPEcGYfV9glqAPzClqXaQPg+J2T4iLwXcMAHrREX+Jbx9CcMPcR+k9VamQDHXUyOa6jcFXpaY92bVpOkSFkAV4GO1Xy1KGH8w4mvS4fiOlxboeCZtU7MIFc6ByynVXW5zKNlZlPCAOg8g1svxBiAgDgJiHRli0QaI3zfgf5MtrMHz80/wCxPM+7L9j8scGEwYLW2otZWutQasJpuD358FsaBxV2DsZv3+CIpqoQ7qrNxah7hgdKfMXNp5Inj7k6xhrtE2kPUYXwE7xhqpYSFWLMJ0fXFl/QlpopsYAwDwenbe3aVz39npQIY5D7wzhR0vPaZ7ZYekEFB+vpmlRkdmKC2YYVD89IojvtzA+k7uItZZ7QxlX5zKLSbFXzE6fAfm4bdbWn/EWBcvAv6jLSnkc/MaCjKt9tx647CrPJF0ubGql1Ri7ZRri+XMLgvuy6ruOCaQHfmVNGX0MxHHuP9Rb6HTRA5X4nDJvdD1eDvNIdw9L/AKJQjy5gAAaIgodMC5eVVzuQDN/hleaa0St6SWH5/wAT6x+8FPl/MPzIHZfqiRgLPKk4JrDpTvBnUOCq1X9pVG+slJ+r/aLeJzGBvFPj4ikEkozasItsAAVBwFz/AJP9p+7/AGn7v95/xP7T/g/2iv8AT/aUmH1aH3l8iaCT2EH3uAAMUARU2MK+aNAFXzaxe/1eY778/wCpv/b/ANRV92Ef09JsMbjA0cAfqGI5fSbE4R5Em/qwnUgFKCx9FOpmcG/F3DIye9R3t15uULq+TUDV7PDLCYeTpEvCWRkLdSC4CDIzLdXNP9ynbBqy/rLud6MUEpG27Xv6mxs+A6rK67zlofGX9xLt72LX3og6JtAfiUgnBNXxc6PyQftFoyqws+CZ9oGA7uLgU7aiwTUXNHaa82x65ce2PpM3Xs4jbBfdm9zQV9Jwu91ivbTwYIrlexKKh5lq0gFiMqW7eo2l0Qr0IFZXhOSUNjBMaUiKLNPqr6NzEO0zfGNyvs1KG8XmAUFdjGxLHXUwvEdHWVoxe6CSg55iCylHaz8vQUmBancLPGdcAz5gWzGNuvb+FxZM+a6nBMub99fEITBmXaW77AIbUqlHeZmZmVK9D2xblurC8rlr4WU5ZlduwvD6rIgs0zXoawcj8xAViouMWrXJsgGhXq2RUsVxdUBM63TL/N8wFFeQ4/e8rvm1QQ7bYPG5uq1Bz05byYYV3WcdJko5zV3iou+LVvAg1niK5Qtf5FKPemVxXBWqzK9jJrkj1hMC28tNPaEUzVDffxLALygNrQE29pnIKi72s+h8SynhYfeHEV7uCYi6OhM3h3YfLlFgiWiIOrWpRDNq+BgvmomKgtEaHYlG2WdkP4MPBsuPiEXBrmDYOxhut8EJDNuYFANE2+JotVdGK2HMclTNuMwL8H1mF+ekd8+0v7T7vXiW9yBjNoiS4H1/ajIiUsOMWrJzmBirvQFHoq641qaq0EpNYaarIBsmQ22s1AEo1g3ET6AWviKbsqu94b8C6vjDwIWrePogRkaMeuhQ8nmLqkOVSuW2Q3n4g7oBqV4knAOOuoAQQ9LZlKi1pK77UvXuFf2WUYVGkcIdDsuqbtzi/lSewKYt0fDXWUSiUSvUQX2Pw+gJmfHjOz1fApznU6DfmJfpfsQ67tcr6Je8/wAVAy1OpnoZn+9AtqlAEuICZMWG65+kGVilumZrO2t7ilYEBhzdDHmVWifhjtQ9okyCpI4DL2iToKisqpvJEoXOkO62q+kugCFgDV2Uypic2RXi0GZi0sWTqVVekYNrRo4aG/ufMd46zRU525TYCVquIqdo9AcB3Zrww6EoWJlhV4LFba8RMqwBsTIhbsNUGcdbL4ixtJN8WLh70yIFbEVmzmD5sYabxB4Q6ctvMfacB/dEa9Ai3JVYlmG8LXS34RbQdDecS/HMBKoabl6MXaHDJm40lDaPV5DGXB3GAEhQDvii/aWW8gl4UkQ5ACPxwEiprCm1vVVv2ikGaXWX4yj4CUYR6Q6P2nYloQhSWNxDrMbbp1ELZ/pLdJeWm77/AG9CZHvUe0IQszjCm/eL3yJNnMWgbgP4AQEkUbA33iDtoFl+UiNaZlolGeU6LQCgx9KvXKUW7CVguX6ENpebrGQj1a4OipVkusbhydaC1DM13uOh1ZhUq6gd11vmxoCZAKAuMo9wIwUwQvJabA4GeHm1KxAMZVQncJTrKXsljOwX2lujG3AQB6R8sJYbmcK1NkrxAKUljMAN7Oj6IJTkgGge38tOeCA3PdnBB2iNkvmO3Cbl1QwUvn9LhNS+i1MxJrNVqMZaiKsKwbDpTnnNkJcnmKeCiivMEU7bHksKrOO8LoRZZHIbTPDA7Foe1e29Bu2jEy0GAUNZPDV6YroBpiHoNBElVOX95i11Ig8OX3jTIYO+oZlHM6WYDAkERw7D2Avw9Y69i5yptWU4zLXbiZVACcFHB7/aIO2UbR2q+lv2hr0WX2nrmseDmOKpA6VUVjBy3L7siVDDk1Re+vovaIWqxyNMl5dqsQHDkPaIltUZGcVLiCAg9QPexv3jj9jaoRvtCAABAcZRxjhBoBY64+kodBx1ma7XcETLquFgz1v7wd3c7ZAXykGCQKm3IDcLCFo/wrhej6L938Pvvt6E5PDLMiHcYwg+cTA2PQyxcLh0Ny7MeCZ9B0ZfmUpfcxhBlCXvB/EOqB8XBbyUW0alBqU+haoV0C429oqwwwUusJVslygvvA5OWPnvmOkGyzI6fVxvE2I9oHRfMVoQ7RZwkZ3CbgBgljCg9LlQkpDYnDK3VEDtbyYxqGpZ0XTdmIhi8WD3v7kQtoA17e20cdIqlcAtn/YzbVS+ZU14NSjEDFh37zmyuhuchLA2i5WgBwXz3Yq2FqDhek/cRsandhsKs/RGaDQG6InsAO0UVW9bUIL9oDAjmU4RTjFIjxiEivqWyk0nD7PaHEUFe7bwffwRr5AM1lC7yL8QJAKdiqAb16EhWl5nd1CQrWxaaKrsdoAqJd6jrDRgFEGoFPLXiWlfvswaAOW6xE0aCE0KsukxSzBMl9o7vesNC8cY7sBTkAAC+wwtJDveBL8DthECmNXI1fSLqXjuKQp2sZ2EMYB5ZoH1Q65OoxVw/mKAYcqy0qRjtaUNthnPGBxjv8nwy6lWQtoin4SKzVEgNLKqdftFSRXZjBpOnRYJIbEYCqdR8RhCiV7ReoYDAD4lQTV1BaXWP3EP9dlzWK3bJ9YjFUji9h+KmCD/AJzClqO3o9J2/wCTFXTDDWKIdV+naByGExac1EXClVxfGJf0LLU+CFLYWGioPvXwy1h0LzsPxDsUINt5hMF63WPyftxT9oNCWFXUWcQBSrB2iG2eequYBQsIc7s9391BRgAGBxlDdJfR7I2zgdJoBUo6RHlxNBicnjpMKS9DMSYAOmJ5LLPEROvOEgDiVKj1aGMcwYktmm4jZsOpkjxWnXRgCC0fLr7fRAKvpTEEaHWKIO6qW0Sn6wdL8ihhVAcIJFOGOgYlizICj/mASIbd3fR6kZBwnQpl8n3TT5ebiljzuM0WIQkN0SDgstTi6UvvFUqbdrD7ZFDQvuzBJroYg+6GBimVMomDF2ESwzwzn73goyr5Zm5UqaTq1cH1lYS6stQroZh0YFA2W8EWdAcrzHAq8VTKEXzOkrqEGGIKjtGusooaT90LL0za3N+de8EZihYjAZF1z7y9Q9i+Raxe/kjvV1FMnXidyAIhP0vaLf8ApSV4yWCs8vWPyekoG78694RAYWJGCrLrzLWhiVvWzWL8dSGBOg8RKgwT7Z0P72l4UdORK2dSJnjcpjXilAKBTgIXaQAaq2uIqpF4TFutcv5jjuKOgYD4iKqaFWh+n/IMERLo/j/eIsRaXq5gcmHuJPpX2Sru0T1Puf1zGfpxOBTQQX+jlPYPxegAmgHWKPmSFcuXlYcgWQ51oGAGLUUFFhBvmo0kcXhHwXj9n4EJkZ7R+KaDZdLSSqE6WWWnCx5IVuFQrYacmGPsR0AO6gjESqsAbaR+kWsX4CLlwcqWDSJ2TD7QxWI6ZfF2GNpU54JqxS6q71zVQBp0iGVMFtyOpkuEHWLHNiHFXHBSsroWmrlEx7gr3blWbSwaWiBayOehHOB/ESOADmVx7KfR4/uUo1ZDnsMFPrQ0q43/AMgWyk2mXVfpKSF0qgiWb9KZSxyzjBUSWg8s3ZUXZUdtxLaV7zQEQ51CbaxzORB01EymngjuIRuVmmiXDvKiQHzGoJfAZUqAW/lJc0KUsvmWZsy9olOwBPcWwJQYdnZiU6tDpFBXJcpxlIfF6hAsCrF9EGB6Md+KPApqdkdDj4jZTbs4iSdo65WyLwUFHSRi1KjyvLKmahOr6LhNUDtEFiDwKaiNLCk6O5aEB1YNLAhXQ7qIW1YqN9iYRjzD4juh6WR+yl/yO1QRL2O+IUILTdce7DhetSc3uJjbXY9GN1Zk2xSB2rgj9X2DZHaKVLyswF3SqDMA9AjFq+gaJTqCH9fmCxJVLbdXelFPrhCqC6Ls7N1LRApD6ozSMi4LNJ3wfBAWXUek09c19OsoIuKNDAPYA9pjYEDYs2hzE2QQuY2l9CJ2LGjLBEM1XtHYMNBfVLdGOdEfguLNBsfN38EY7McdVj5+JSDWZ1zquvPxHYYCuJdALjL40OirVhtrfe4SN4ymbEsr2ynIhwbgLFC4SEjbi8TdNpuuCKLNQ03GslHxFgkCm/w4+kzFkCBtT7SvnQPV48wIJsgUOThA+7B9ibHwk19fQyy+C7nLFrRe8Oi5x0p3B80QlPEJnCnQSjsqbHcaQgZi10crB031lJuKBa0RXSdZntmU7dejQnWDbHencrAay/EyDnMoDob8S0MI36VGrQsnn4GV/YDqdJfXSBl47ycMevnNUOHAx1CzC8ccrOvDLEkIxWL0vsPDUAdD095284d2Z/uSwq2YqjAQocqSvLyQiUwvMLfphpKvDmg4ueBbmbvT5y7aGPR81kki8Lrt3Db2gmhFtG13XMCUP4APTSwqhRt+IiqF22KkdKRAiZCEIG/qzHh91Is0DdF/SMaESNpqzZBsKWNxFW/rvGOmwLbyPEpu8MBtqyPXq0gt1fMqzcAB4CNwMCg7FC/iz3ZQShFba4CGiNtzMd8MqeLRbuODvcQZAlYDV07lctScq97xR9IKCFQ5HSHnFBKoOI4AaGxOIsAuHdzCkUvdjj3LIRkNgZLo7ZuFA+ugqVmEET7nhwSxrBvF2wg7HNfl3+ZlIKF5wAfiDNv1jOAmwgOItxg7w1hfdjVs9o/0J0tZYl0RaNnsDrKCghWWSqInoxwnUiBbQdZmEwN9z+HVyrI+ppzfSbgchXMJnJodoAJY6YGoBDQXah6KtPJZhmb1dGWxLcrbMry9vWWtgcuh5Y+RFiIHzt+nrvWQ7rUrJOOvxs/WGEHFOfsfN+Ii58L9jpCmnOS9xUQBkOSCB04LxCAFTSXhStXuophtt59ukaEb7mLY5sNMAZ00+Ox3YUQFA4I6guU0Pfr7RVVVXd+iuG3rwQLst1fRIIPRfS3KZestecsDXL06wQtj606MNnWUi4ODrBKDXeHKLdOGPE2bOsApYXfWWgFdTIwzYKni7bPOpWCOBjuOTYwoJ7sxAjwLcarBblmPJdn/AF7wO3AGV8BmEkUVmkLPtA0zVWa1vvBsKwOLuYtiTdlT1L9AMenl4jV31huAshMThNPRr8zj0mbk1hxNPmfW/wAeXn8z6chPcjfejbeZ9P6dZz6/ouh6PpZQYNPuwEafDN+Z9AQCoNkA29Z9nPpJw+fxPoJXsMlrlt36dPiJ9v8AdnSff/iY+rd4nKPPpfQH8P79CbvafdT+pXYct+CEVfETzF1Zf26lRywjpZfMs8pTPO5icNseI3e735Q9K/74aPE//9k=$domain=reporter.mk -CSS-generic: 2 plain CSS selectors -CSS-specific: 426 distinct filters - Combined into 114 distinct hostnames - Combined into 0 distinct entities -CSS-declarative: 2 distinct filters - Combined into 2 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'nld-0': - Fetching remote https://easydutch-ubo.github.io/EasyDutch/EasyDutch.txt - Fetching remote https://easydutch-ubo.github.io/EasyDutch/EasyDutch/Block_General.txt - Fetching remote https://easydutch-ubo.github.io/EasyDutch/EasyDutch/Block_first_party_Server.txt - Fetching remote https://easydutch-ubo.github.io/EasyDutch/EasyDutch/Block_third_party_Server.txt - Fetching remote https://easydutch-ubo.github.io/EasyDutch/EasyDutch/Block_Resources.txt - Fetching remote https://easydutch-ubo.github.io/EasyDutch/EasyDutch/Block_Whitelist.txt - Fetching remote https://easydutch-ubo.github.io/EasyDutch/EasyDutch/Hide_General.txt - Fetching remote https://easydutch-ubo.github.io/EasyDutch/EasyDutch/Hide_Specific.txt - Fetching remote https://easydutch-ubo.github.io/EasyDutch/EasyDutch/Hide_Whitelist.txt - Fetching remote https://easydutch-ubo.github.io/EasyDutch/EasyDutch/Anti-Adblock.txt - Fetching remote https://easydutch-ubo.github.io/EasyDutch/EasyDutch/No_uBlock_Filters.txt -Input filter count: 734 - Accepted filter count: 733 - Rejected filter count: 0 -Output rule count: 626 - Plain good: 615 - - Maybe good (regexes): 6 - redirect=: 2 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 3 - FilterStrictParty: Strict partyness strict3p not supported - regexFilter is not RE2-compatible: https\:\/\/nieuwsfiets\.nu\/wp-content\/uploads\/.*\/.*(?:banner-(?!mis|tip).*|\.gif) - Can't salvage rule with only entity-based domain= option: allestoringen.* -CSS-generic: 14 plain CSS selectors -CSS-generic-high: 1 plain CSS selectors -CSS-specific: 956 distinct filters - Combined into 994 distinct hostnames - Combined into 1 distinct entities -CSS-declarative: 11 distinct filters - Combined into 10 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 244 distinct combined selectors - Combined into 221 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'nor-0': - Fetching remote https://raw.githubusercontent.com/DandelionSprout/adfilt/master/NorwegianList.txt - Fetching remote https://raw.githubusercontent.com/DandelionSprout/adfilt/master/NorwegianExperimentalList%20alternate%20versions/AntiAdblockEntries.txt - Fetching remote https://raw.githubusercontent.com/DandelionSprout/adfilt/master/NorwegianExperimentalList%20alternate%20versions/NordicFilters-NotFirefox.txt - Fetching remote https://raw.githubusercontent.com/DandelionSprout/adfilt/master/NorwegianExperimentalList%20alternate%20versions/NordicFilters-NotBrave.txt -Input filter count: 1400 - Accepted filter count: 1400 - Rejected filter count: 0 -Output rule count: 505 - Plain good: 459 - - Maybe good (regexes): 4 - redirect=: 5 - removeparams= (accepted/discarded): 25/4 - modifyHeaders=: 1 - Unsupported: 11 - Can't salvage rule with only entity-based domain= option: eniro.* - Can't salvage rule with only entity-based domain= option: eniro.*|proff.* - Can't salvage rule with only entity-based domain= option: eurosport.* - Can't salvage rule with only entity-based domain= option: discoveryplus.* - Can't salvage rule with only entity-based domain= option: discoveryplus.* - Can't salvage rule with only entity-based domain= option: discoveryplus.* - Can't salvage rule with only entity-based domain= option: discoveryplus.* - Unsupported regex-based removeParam: /^rs\d/ - Unsupported regex-based removeParam: /^source=partnerads$/ - Unsupported regex-based removeParam: /^source=tradedoubler$/ - Unsupported regex-based removeParam: /^amp;/ -CSS-generic: 132 plain CSS selectors -CSS-generic-high: 28 plain CSS selectors -CSS-specific: 1127 distinct filters - Combined into 580 distinct hostnames - Combined into 13 distinct entities -CSS-declarative: 48 distinct filters - Combined into 117 distinct hostnames - Combined into 1 distinct entities -Procedural-related distinct filters: 92 distinct combined selectors - Combined into 80 distinct hostnames - Combined into 2 distinct entities -============================ -Listset for 'pol-0': - Fetching remote https://raw.githubusercontent.com/MajkiIT/polish-ads-filter/master/polish-adblock-filters/adblock.txt - Fetching remote https://raw.githubusercontent.com/olegwukr/polish-privacy-filters/master/anti-adblock.txt - Fetching remote https://raw.githubusercontent.com/MajkiIT/polish-ads-filter/master/polish-adblock-filters/adblock_ublock.txt - Fetching remote https://raw.githubusercontent.com/olegwukr/polish-privacy-filters/master/anti-adblock-suplement.txt -Input filter count: 1409 - Accepted filter count: 1408 - Rejected filter count: 1 -Output rule count: 1046 - Plain good: 967 - - Maybe good (regexes): 43 - redirect=: 27 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 9 - regexFilter is not RE2-compatible: \/[0-9a-zA-Z]{5,7}\_(?!adaptiveresize)[a-z]{12,17}\_[0-9]{3,3}\x[0-9]{3,3}\.jpg$ - regexFilter is not RE2-compatible: ^https:\/\/eku24.net\/images\/slajdy\/(?!zyczenia)[a-z]{3,10}\/[a-zA-Z0-9_-]{10,50}\.jpg - regexFilter is not RE2-compatible: ^https:\/\/(?!horrortube)(?!filman.cc)(?!horlol.pl)[a-z.0-9]{3,15}\.[a-z]{2,3}\/ - regexFilter is not RE2-compatible: https?:\/\/naekranie\.pl\/wp-content\/uploads\/[0-9]{4,4}\/[0-9]{2,2}\/(?!jpg)[0-9a-z]{7,10}$ - regexFilter is not RE2-compatible: https?:\/\/(?!(poczta|bc))[a-z.]{3,15}\.wp\.pl\/.{20,} - regexFilter is not RE2-compatible: ^http:\/\/((?!192\.168)(?!10\.)(?!172\.16)(?!172\.17)(?!172\.18)(?!172\.19)(?!172\.2)(?!172\.30)(?!172\.31)([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\/[a-zA-Z0-9]{30,} - regexFilter is not RE2-compatible: ^(http|https):\/\/www\.portel\.pl\/(?!pasaz)[-a-z0-9A-Z_%$&+=[\].]{1,200}\/[-a-z0-9A-Z_%$&+=[\]/.]{2,200}.(html|htm) - regexFilter is not RE2-compatible: ^(http|https):\/\/(?!www.speedvid)(?!streamcherry.com)(?!vshare)(?!vidoza)(?!www.youtube)[a-zA-Z0-9\W]{5,10}.[a-z]{2,20}\/(?!anime)[\w\W\d]{5,20}\/[a-z]{5,20}\/ - Can't salvage rule with only entity-based domain= option: trojmiasto.* -CSS-generic: 63 plain CSS selectors -CSS-generic-high: 48 plain CSS selectors -CSS-specific: 4214 distinct filters - Combined into 3231 distinct hostnames - Combined into 0 distinct entities -CSS-declarative: 131 distinct filters - Combined into 182 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 96 distinct combined selectors - Combined into 95 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'rou-1': - Fetching remote https://road.adblock.ro/lista.txt -No valid content for undefined -Input filter count: 0 - Accepted filter count: 0 - Rejected filter count: 0 -Output rule count: 0 - Plain good: 0 - - Maybe good (regexes): 0 - redirect=: 0 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 0 - -============================ -Listset for 'rus-0': - Fetching remote https://raw.githubusercontent.com/easylist/ruadlist/master/RuAdList-uBO.txt - Fetching remote https://raw.githubusercontent.com/easylist/ruadlist/master/advblock/adservers.txt - Fetching remote https://raw.githubusercontent.com/easylist/ruadlist/master/advblock/first_level.txt - Fetching remote https://raw.githubusercontent.com/easylist/ruadlist/master/advblock/general_block.txt - Fetching remote https://raw.githubusercontent.com/easylist/ruadlist/master/advblock/general_hide.txt - Fetching remote https://raw.githubusercontent.com/easylist/ruadlist/master/advblock/popup.txt - Fetching remote https://raw.githubusercontent.com/easylist/ruadlist/master/advblock/specific_antisocial.txt - Fetching remote https://raw.githubusercontent.com/easylist/ruadlist/master/advblock/specific_block.txt - Fetching remote https://raw.githubusercontent.com/easylist/ruadlist/master/advblock/specific_hide.txt - Fetching remote https://raw.githubusercontent.com/easylist/ruadlist/master/advblock/specific_special.txt - Fetching remote https://raw.githubusercontent.com/easylist/ruadlist/master/advblock/thirdparty.txt - Fetching remote https://raw.githubusercontent.com/easylist/ruadlist/master/advblock/whitelist.txt - Fetching remote https://raw.githubusercontent.com/easylist/ruadlist/master/css-fixes-experimental.txt - Fetching remote https://raw.githubusercontent.com/easylist/ruadlist/master/js-fixes-experimental.txt - Fetching remote https://raw.githubusercontent.com/easylist/ruadlist/master/AWRL-non-sync.txt -Input filter count: 17309 - Accepted filter count: 17299 - Rejected filter count: 8 -Output rule count: 5832 - Pruning requestDomains: from 6634 to 6633 - Plain good: 5745 - - Maybe good (regexes): 21 - redirect=: 16 - removeparams= (accepted/discarded): 15/2 - modifyHeaders=: 29 - Unsupported: 6 - regexFilter is not RE2-compatible: ^(?!.*(24liveblog.com|24liveplus.com|acint.net|addthis.com|addthisedge.com|akamai.net|akamaiedge.net|alloha.tv|ampproject.org|anycomment.io|apester.com|api-ssl.bitly.com|api.corr.life|api.here.com|api.sypexgeo.net|app.hoversignal.com|appsmail.ru|bam.nr-data.net|blogger.com|bootstrapcdn.com|cackle.me|cdn.ampproject.org|cdn.iframe.ly|cdn.rawgit.com|cdnstats.ru|cdnvideo.ru|chartbeat.com|chatango.com|chatbro.com|chimpstatic.com|cloudflare.com|cloudflare.net|cloudfront.net|cloudfunctions.net|code.createjs.com|columbus.te.ua|cultserv.ru|disqus.com|disquscdn.com|dmca.com|documentcloud.org|each.im|ebacdn.com|edgecastcdn.net|edgecdn.ru|ellinagraypel.com|embed.ex.co|embed.widgetpack.com|embedstorage.net|eurosolidarity.org|facebook.com|facebook.net|fastly.net|fastlylb.net|fbcdn.net|fbvkcdn.com|feonet.net|fluidplayer.com|fontawesome.com|fonts.w.tools|freecurrencyrates.com|fwcdn1.com|fwdcdn.com|gcdn.co|getsitecontrol.com|gismeteo.ru|github.io|gitlab.io|google-analytics.com|google.com|googleadservices.com|googleapis.com|googleoptimize.com|googletagmanager.com|googletagservices.com|gravatar.com|gravitec.media|gravitec.net|gstatic.com|hcaptcha.com|hupso.com|hwcdn.net|hypercomments.com|ibytedtos.com|imgsmail.ru|imgur.com|informers.ukr.net|instagram.com|intensedebate.com|intercom.io|intercomcdn.com|intravideo.net|issuu.com|ivideon.com|jivosite.com|jquery.com|js-agent.newrelic.com|jsdelivr.net|jsonip.com|jwpcdn.com|jwplatform.com|keycaptcha.com|kin-x.com|kinogram.best|kinohod.ru|kinoplayer.co|kinotreiler.com|kitbit.net|kodik-add.com|kodikapi.com|libria.fun|licdn.com|likebtn.com|linkedin.com|lp4.io|mail.ru|mailchimp.com|mapbox.com|media-imdb.com|media.reformal.ru|mediator.media|meteobar.com|meteonova.ru|mirtesen.ru|netdna-cdn.com|ngenix.net|nuipogoda.ru|odnaknopka.ru|odnoklassniki.ru|ok.ru|oneall.com|onesignal.com|onthe.io|parastorage.com|phnx.click|piktochart.com|pinterest.com|pixars.org|platformcraft.ru|playbuzz.com|player|player.panda.video|pljs.ru|plrjs.com|pluso.ru|plyr.io|polldaddy.com|polyfill.io|pv.pjtsu.com|quiz.ink|raincaptcha.com|readymag.com|recaptcha.net|relap.io|ren.tv|renteres.ru|rumer.club|s5o.ru|securedtouch.com|selcdn.net|sendpulse.com|sentry-cdn.com|shareaholic.com|shareaholic.net|sharethis.com|shrink.pe|sinoptik.ua|source.mmi.bemobile.ua|sporcle.com|sportradar.com|sportrecs.com|sports.ru|stackpathcdn.com|static.addtoany.com|statically.io|streamvid.club|telegram.im|telegram.org|tenews.org.ua|tenews.te.ua|tiktok.com|tilda.ws|tildacdn.com|tns-counter.ru|tolstoycomments.com|traq.li|trbcdn.net|trbna.com|ttrace.ru|ttwstatic.com|tumblr.com|tvget.ru|tvsok.ru|twimg.com|twitter.com|typekit.net|uanews.org.ua|unpkg.com|uptolike.com|userapi.com|usocial.pro|uweb.ru|vicomi.com|vidazoo.com|videocdn.tv|videoplayers.club|viglink.com|viqeo.tv|vk.com|vkontakte.ru|vuukle.com|webflow.com|weblium.com|weblium.site|widget.speechki.org|widget.vp.ru|widgets.getpocket.com|world-weather.ru|wp.com|yabber.cloud|yandex.ru|yandex.st|yastatic.net|yohoho.cc|yohoho.online|yoomoney.ru|yourwebsite.life|youtube-nocookie.com|youtube.com|ytimg.com|zencdn.net)).*$ - regexFilter is not RE2-compatible: ^(?!.*(24liveblog.com|24liveplus.com|acint.net|addthis.com|addthisedge.com|akamai.net|akamaiedge.net|alloha.tv|ampproject.org|anycomment.io|apester.com|api-ssl.bitly.com|api.corr.life|api.here.com|api.sypexgeo.net|app.hoversignal.com|appsmail.ru|bam.nr-data.net|blogger.com|bootstrapcdn.com|cackle.me|cdn.ampproject.org|cdn.iframe.ly|cdn.rawgit.com|cdnstats.ru|cdnvideo.ru|chartbeat.com|chatango.com|chatbro.com|chimpstatic.com|cloudflare.com|cloudflare.net|cloudfront.net|cloudfunctions.net|code.createjs.com|columbus.te.ua|cultserv.ru|disqus.com|disquscdn.com|dmca.com|documentcloud.org|each.im|ebacdn.com|edgecastcdn.net|edgecdn.ru|ellinagraypel.com|embed.ex.co|embed.widgetpack.com|embedstorage.net|eurosolidarity.org|facebook.com|facebook.net|fastly.net|fastlylb.net|fbcdn.net|fbvkcdn.com|feonet.net|fluidplayer.com|fontawesome.com|fonts.w.tools|freecurrencyrates.com|fwcdn1.com|fwdcdn.com|gcdn.co|getsitecontrol.com|gismeteo.ru|github.io|gitlab.io|google-analytics.com|google.com|googleadservices.com|googleapis.com|googleoptimize.com|googletagmanager.com|googletagservices.com|gravatar.com|gravitec.media|gravitec.net|gstatic.com|hcaptcha.com|hupso.com|hwcdn.net|hypercomments.com|ibytedtos.com|imgsmail.ru|imgur.com|informers.ukr.net|instagram.com|intensedebate.com|intercom.io|intercomcdn.com|intravideo.net|issuu.com|ivideon.com|jivosite.com|jquery.com|js-agent.newrelic.com|jsdelivr.net|jsonip.com|jwpcdn.com|jwplatform.com|keycaptcha.com|kin-x.com|kinogram.best|kinohod.ru|kinoplayer.co|kinotreiler.com|kitbit.net|kodik-add.com|kodikapi.com|libria.fun|licdn.com|likebtn.com|linkedin.com|lp4.io|mail.ru|mailchimp.com|mapbox.com|media-imdb.com|media.reformal.ru|mediator.media|meteobar.com|meteonova.ru|mirtesen.ru|netdna-cdn.com|ngenix.net|nuipogoda.ru|odnaknopka.ru|odnoklassniki.ru|ok.ru|oneall.com|onesignal.com|onthe.io|parastorage.com|phnx.click|piktochart.com|pinterest.com|pixars.org|platformcraft.ru|playbuzz.com|player|player.panda.video|pljs.ru|plrjs.com|pluso.ru|plyr.io|polldaddy.com|polyfill.io|pv.pjtsu.com|quiz.ink|raincaptcha.com|readymag.com|recaptcha.net|relap.io|ren.tv|renteres.ru|rumer.club|s5o.ru|securedtouch.com|selcdn.net|sendpulse.com|sentry-cdn.com|shareaholic.com|shareaholic.net|sharethis.com|shrink.pe|sinoptik.ua|source.mmi.bemobile.ua|sporcle.com|sportradar.com|sportrecs.com|sports.ru|stackpathcdn.com|static.addtoany.com|statically.io|streamvid.club|telegram.im|telegram.org|tenews.org.ua|tenews.te.ua|tiktok.com|tilda.ws|tildacdn.com|tns-counter.ru|tolstoycomments.com|traq.li|trbcdn.net|trbna.com|ttrace.ru|ttwstatic.com|tumblr.com|tvget.ru|tvsok.ru|twimg.com|twitter.com|typekit.net|uanews.org.ua|unpkg.com|uptolike.com|userapi.com|usocial.pro|uweb.ru|vicomi.com|vidazoo.com|videocdn.tv|videoplayers.club|viglink.com|viqeo.tv|vk.com|vkontakte.ru|vuukle.com|webflow.com|weblium.com|weblium.site|widget.speechki.org|widget.vp.ru|widgets.getpocket.com|world-weather.ru|wp.com|yabber.cloud|yandex.ru|yandex.st|yastatic.net|yohoho.cc|yohoho.online|yoomoney.ru|yourwebsite.life|youtube-nocookie.com|youtube.com|ytimg.com|zencdn.net)).*$ - regexFilter is not RE2-compatible: ^(?!.*(spac.me)).*$ - regexFilter is not RE2-compatible: ^(?!.*(24liveblog.com|24liveplus.com|acint.net|addthis.com|addthisedge.com|akamai.net|akamaiedge.net|alloha.tv|ampproject.org|anycomment.io|apester.com|api-ssl.bitly.com|api.corr.life|api.here.com|api.sypexgeo.net|app.hoversignal.com|appsmail.ru|bam.nr-data.net|blogger.com|bootstrapcdn.com|cackle.me|cdn.ampproject.org|cdn.iframe.ly|cdn.rawgit.com|cdnstats.ru|cdnvideo.ru|chartbeat.com|chatango.com|chatbro.com|chimpstatic.com|cloudflare.com|cloudflare.net|cloudfront.net|cloudfunctions.net|code.createjs.com|columbus.te.ua|cultserv.ru|disqus.com|disquscdn.com|dmca.com|documentcloud.org|each.im|ebacdn.com|edgecastcdn.net|edgecdn.ru|ellinagraypel.com|embed.ex.co|embed.widgetpack.com|embedstorage.net|eurosolidarity.org|facebook.com|facebook.net|fastly.net|fastlylb.net|fbcdn.net|fbvkcdn.com|feonet.net|fluidplayer.com|fontawesome.com|fonts.w.tools|freecurrencyrates.com|fwcdn1.com|fwdcdn.com|gcdn.co|getsitecontrol.com|gismeteo.ru|github.io|gitlab.io|google-analytics.com|google.com|googleadservices.com|googleapis.com|googleoptimize.com|googletagmanager.com|googletagservices.com|gravatar.com|gravitec.media|gravitec.net|gstatic.com|hcaptcha.com|hupso.com|hwcdn.net|hypercomments.com|ibytedtos.com|imgsmail.ru|imgur.com|informers.ukr.net|instagram.com|intensedebate.com|intercom.io|intercomcdn.com|intravideo.net|issuu.com|ivideon.com|jivosite.com|jquery.com|js-agent.newrelic.com|jsdelivr.net|jsonip.com|jwpcdn.com|jwplatform.com|keycaptcha.com|kin-x.com|kinogram.best|kinohod.ru|kinoplayer.co|kinotreiler.com|kitbit.net|kodik-add.com|kodikapi.com|libria.fun|licdn.com|likebtn.com|linkedin.com|lp4.io|mail.ru|mailchimp.com|mapbox.com|media-imdb.com|media.reformal.ru|mediator.media|meteobar.com|meteonova.ru|mirtesen.ru|netdna-cdn.com|ngenix.net|nuipogoda.ru|odnaknopka.ru|odnoklassniki.ru|ok.ru|oneall.com|onesignal.com|onthe.io|parastorage.com|phnx.click|piktochart.com|pinterest.com|pixars.org|platformcraft.ru|playbuzz.com|player|player.panda.video|pljs.ru|plrjs.com|pluso.ru|plyr.io|polldaddy.com|polyfill.io|pv.pjtsu.com|quiz.ink|raincaptcha.com|readymag.com|recaptcha.net|relap.io|ren.tv|renteres.ru|rumer.club|s5o.ru|securedtouch.com|selcdn.net|sendpulse.com|sentry-cdn.com|shareaholic.com|shareaholic.net|sharethis.com|shrink.pe|sinoptik.ua|source.mmi.bemobile.ua|sporcle.com|sportradar.com|sportrecs.com|sports.ru|stackpathcdn.com|static.addtoany.com|statically.io|streamvid.club|telegram.im|telegram.org|tenews.org.ua|tenews.te.ua|tiktok.com|tilda.ws|tildacdn.com|tns-counter.ru|tolstoycomments.com|traq.li|trbcdn.net|trbna.com|ttrace.ru|ttwstatic.com|tumblr.com|tvget.ru|tvsok.ru|twimg.com|twitter.com|typekit.net|uanews.org.ua|unpkg.com|uptolike.com|userapi.com|usocial.pro|uweb.ru|vicomi.com|vidazoo.com|videocdn.tv|videoplayers.club|viglink.com|viqeo.tv|vk.com|vkontakte.ru|vuukle.com|webflow.com|weblium.com|weblium.site|widget.speechki.org|widget.vp.ru|widgets.getpocket.com|world-weather.ru|wp.com|yabber.cloud|yandex.ru|yandex.st|yastatic.net|yohoho.cc|yohoho.online|yoomoney.ru|yourwebsite.life|youtube-nocookie.com|youtube.com|ytimg.com|zencdn.net)).*$ - Unsupported modifier exception - Unsupported modifier exception -CSS-generic: 318 plain CSS selectors -CSS-generic-high: 461 plain CSS selectors -CSS-specific: 9772 distinct filters - Combined into 7075 distinct hostnames - Combined into 0 distinct entities -CSS-declarative: 904 distinct filters - Combined into 876 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 271 distinct combined selectors - Combined into 336 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'spa-0': - Fetching remote https://easylist-downloads.adblockplus.org/easylistspanish.txt -Input filter count: 1115 - Accepted filter count: 1115 - Rejected filter count: 0 -Output rule count: 642 - Plain good: 634 - - Maybe good (regexes): 8 - redirect=: 0 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 0 - -CSS-generic: 243 plain CSS selectors -CSS-generic-high: 15 plain CSS selectors -CSS-specific: 1469 distinct filters - Combined into 1198 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 26 distinct combined selectors - Combined into 25 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'spa-1': - Fetching remote https://filters.adtidy.org/extension/ublock/filters/9.txt -Input filter count: 1393 - Accepted filter count: 1387 - Rejected filter count: 0 -Output rule count: 958 - Plain good: 921 - Salvaged rule by ignoring 1 entity-based domain= option: pelisplushd.net|cuevana3.* - Maybe good (regexes): 6 - redirect=: 27 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 4 - Can't salvage rule with only entity-based domain= option: netcine.* - Can't salvage rule with only entity-based domain= option: netcine.* - regexFilter is not RE2-compatible: ^(?!.*(sharecast.ws|bunnycdn.ru|bootstrapcdn.com|cdn.ampproject.org|cloudflare.com|cdn.staticfile.org|disqus.com|disquscdn.com|dmca.com|ebacdn.com|facebook.net|fastlylb.net|fbcdn.net|fluidplayer.com|fontawesome.com|github.io|google.com|googleapis.com|googletagmanager.com|gstatic.com|jquery.com|jsdelivr.net|jwpcdn.com|jwplatform.com|polyfill.io|recaptcha.net|shrink.pe|twitter.com|ulogin.ru|unpkg.com|userapi.com|vidazoo.com|vk.com|yandex.|yastatic.net|ytimg.com|zencdn.net|player|youtube.com|cackle.me|googleoptimize.com|vuukle.com|chatango.com|twimg.com|google-analytics.com|hcaptcha.com|raincaptcha.com|media-imdb.com|blogger.com|hwcdn.net|instagram.com|wp.com|imgsmail.ru)).*$ - Can't salvage rule with only entity-based domain= option: anitube.* -CSS-generic: 84 plain CSS selectors -CSS-specific: 2526 distinct filters - Combined into 1464 distinct hostnames - Combined into 6 distinct entities -CSS-declarative: 99 distinct filters - Combined into 149 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 70 distinct combined selectors - Combined into 65 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'svn-0': - Fetching remote https://raw.githubusercontent.com/betterwebleon/slovenian-list/master/filters.txt -Input filter count: 148 - Accepted filter count: 148 - Rejected filter count: 0 -Output rule count: 100 - Plain good: 100 - - Maybe good (regexes): 0 - redirect=: 0 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 0 - -CSS-generic: 4 plain CSS selectors -CSS-specific: 332 distinct filters - Combined into 148 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 2 distinct combined selectors - Combined into 2 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'swe-1': - Fetching remote https://raw.githubusercontent.com/lassekongo83/Frellwits-filter-lists/master/Frellwits-Swedish-Filter.txt - Fetching remote https://raw.githubusercontent.com/lassekongo83/Frellwits-filter-lists/master/Swedish/swe-ubo-filters.txt - Fetching remote https://raw.githubusercontent.com/lassekongo83/Frellwits-filter-lists/master/Swedish/chromium.txt - Fetching remote https://raw.githubusercontent.com/lassekongo83/Frellwits-filter-lists/master/Swedish/not_mobile.txt -Input filter count: 1663 - Accepted filter count: 1663 - Rejected filter count: 0 -Output rule count: 1241 - Plain good: 1219 - - Maybe good (regexes): 2 - redirect=: 10 - removeparams= (accepted/discarded): 5/3 - modifyHeaders=: 2 - Unsupported: 3 - Unsupported regex-based removeParam: /^ap/ - Unsupported regex-based removeParam: /^browser/ - Unsupported regex-based removeParam: /^utm_/ -CSS-generic: 271 plain CSS selectors -CSS-generic-high: 44 plain CSS selectors -CSS-specific: 661 distinct filters - Combined into 1130 distinct hostnames - Combined into 1 distinct entities -CSS-declarative: 79 distinct filters - Combined into 211 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 374 distinct combined selectors - Combined into 324 distinct hostnames - Combined into 1 distinct entities -============================ -Listset for 'tha-0': - Fetching remote https://raw.githubusercontent.com/easylist-thailand/easylist-thailand/master/subscription/easylist-thailand.txt - Fetching remote https://raw.githubusercontent.com/easylist-thailand/easylist-thailand/master/subscription/ublock.txt -Input filter count: 760 - Accepted filter count: 760 - Rejected filter count: 0 -Output rule count: 750 - Plain good: 746 - - Maybe good (regexes): 2 - redirect=: 2 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 0 - -CSS-generic-high: 5 plain CSS selectors -CSS-specific: 614 distinct filters - Combined into 166 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 14 distinct combined selectors - Combined into 11 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'tur-0': - Fetching remote https://filters.adtidy.org/extension/ublock/filters/13.txt -Input filter count: 1779 - Accepted filter count: 1778 - Rejected filter count: 0 -Output rule count: 1338 - Plain good: 1297 - Salvaged rule by ignoring 1 entity-based domain= option: ajans32.com|asyadiziizle.com|balfilmizle1.com|birasyadizi.com|buyuktorbali.com|dizilost.com|duzcetv.com|erotikfilmtube.com|erotikizlefilm.com|ertehaber.com|filmjr1.com|filmsezonu.com|haber32.com.tr|haberant.com|jokerfilmizle.com|kozfilm.com|malatyamegahaber.com|medya32.com|sexfilmleriizle.com|sinemangoo.org|technopat.net|unyenethaber.com|zerotikk.com|dizicaps.* - Salvaged rule by ignoring 1 entity-based domain= option: fullhdfilm.pro|fullhdfilmizle5.* - Salvaged rule by ignoring 1 entity-based domain= option: turkcealtyazi.org|filmmakinesi.* - Salvaged rule by ignoring 1 entity-based domain= option: cdn.diziyou.co|geyvemedya.com|hdfilmcehennemi2.* - Salvaged rule by ignoring 1 entity-based domain= option: forum.donanimhaber.com|mp3indirdur.mobi|setfilmizle.* - Maybe good (regexes): 14 - redirect=: 17 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 10 - Can't salvage rule with only entity-based domain= option: filmizletv.* - Can't salvage rule with only entity-based domain= option: fullhdfilmizle5.* - Can't salvage rule with only entity-based domain= option: jetfilmizle.* - Can't salvage rule with only entity-based domain= option: siyahfilmizle.* - Can't salvage rule with only entity-based domain= option: fullhdfilmizlesene.* - Can't salvage rule with only entity-based domain= option: filmmakinesi.* - regexFilter is not RE2-compatible: yenihaberden.com\/d\/other\/(?!yeni-haber-youtube) - Can't salvage rule with only entity-based domain= option: yabancidizi.* - regexFilter is not RE2-compatible: ^(?!.*(sharecast.ws|bunnycdn.ru|bootstrapcdn.com|cdn.ampproject.org|cloudflare.com|cdn.staticfile.org|disqus.com|disquscdn.com|dmca.com|ebacdn.com|facebook.net|fastlylb.net|fbcdn.net|fluidplayer.com|fontawesome.com|github.io|google.com|googleapis.com|googletagmanager.com|gstatic.com|jquery.com|jsdelivr.net|jwpcdn.com|jwplatform.com|polyfill.io|recaptcha.net|shrink.pe|twitter.com|ulogin.ru|unpkg.com|userapi.com|vidazoo.com|vk.com|yandex.|yastatic.net|ytimg.com|zencdn.net|player|youtube.com|cackle.me|googleoptimize.com|vuukle.com|chatango.com|twimg.com|google-analytics.com|hcaptcha.com|raincaptcha.com|media-imdb.com|blogger.com|hwcdn.net|instagram.com|wp.com|imgsmail.ru)).*$ - Can't salvage rule with only entity-based domain= option: filmizletv.* -CSS-generic: 146 plain CSS selectors -CSS-generic-high: 60 plain CSS selectors -CSS-specific: 3395 distinct filters - Combined into 2763 distinct hostnames - Combined into 40 distinct entities -CSS-declarative: 169 distinct filters - Combined into 558 distinct hostnames - Combined into 22 distinct entities -Procedural-related distinct filters: 159 distinct combined selectors - Combined into 128 distinct hostnames - Combined into 3 distinct entities -============================ -Listset for 'vie-1': - Fetching remote https://raw.githubusercontent.com/abpvn/abpvn/master/filter/abpvn_ublock.txt -Input filter count: 567 - Accepted filter count: 567 - Rejected filter count: 0 -Output rule count: 467 - Plain good: 455 - - Maybe good (regexes): 4 - redirect=: 5 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 3 - Unsupported: 0 - -CSS-generic: 10 plain CSS selectors -CSS-generic-high: 4 plain CSS selectors -CSS-specific: 769 distinct filters - Combined into 439 distinct hostnames - Combined into 0 distinct entities -CSS-declarative: 4 distinct filters - Combined into 14 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 4 distinct combined selectors - Combined into 3 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'block-lan': - Fetching remote https://ublockorigin.github.io/uAssets/filters/lan-block.txt -Input filter count: 48 - Accepted filter count: 48 - Rejected filter count: 0 -Output rule count: 12 - Plain good: 5 - - Maybe good (regexes): 7 - redirect=: 0 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 0 - -============================ -Listset for 'dpollock-0': - Fetching remote https://someonewhocares.org/hosts/hosts -Input filter count: 11543 - Accepted filter count: 11542 - Rejected filter count: 0 -Output rule count: 1 - Pruning requestDomains: from 11542 to 9296 - Plain good: 1 - - Maybe good (regexes): 0 - redirect=: 0 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 0 - -============================ -Listset for 'adguard-spyware-url': - Fetching remote https://filters.adtidy.org/extension/ublock/filters/17.txt -Input filter count: 1186 - Accepted filter count: 1183 - Rejected filter count: 0 -Output rule count: 448 - Plain good: 0 - - Maybe good (regexes): 0 - redirect=: 0 - removeparams= (accepted/discarded): 367/81 - modifyHeaders=: 0 - Unsupported: 81 - Unsupported regex-based removeParam: /^cm_mmc/ - Unsupported regex-based removeParam: /^__s=[A-Za-z0-9]{6\,}/ - Unsupported regex-based removeParam: /^via%3D/ - Unsupported regex-based removeParam: /ga[ct]id/ - Unsupported regex-based removeParam: /param[0-9]{1}|utm_si|matchtype|device|creative|keyword|placement|adposition|campaignid|adgroupid|feeditemid|targetid|loc_|searchtype|network|search_pos|cat_pos|block|position/ - Unsupported regex-based removeParam: /pfx|adj/ - Unsupported regex-based removeParam: /^event_callback_/ - Unsupported regex-based removeParam: /elq/ - Unsupported regex-based removeParam: /utm_/ - Unsupported regex-based removeParam: /web_only|_branch_referrer/ - Unsupported regex-based removeParam: /premiumVisit|utm_compaign/ - Unsupported regex-based removeParam: /utm_partner_id|frommail/ - Unsupported regex-based removeParam: /^(udid|DeviceID|ver|appbuild|vendor|model|device_name|device_type|instanceid|device_year|connection_class|appsflyerid)/ - Unsupported regex-based removeParam: /^cd\d+/ - Unsupported regex-based removeParam: /^subid/ - Unsupported regex-based removeParam: /^mkt_tok/ - Unsupported regex-based removeParam: /fx_(source|medium|campaign)/ - Unsupported regex-based removeParam: /^ref_/ - Unsupported regex-based removeParam: /^cx_/ - Unsupported regex-based removeParam: /^pickup_list_click/ - Unsupported regex-based removeParam: /distributorid|wfr|ifr|share_relation/ - Unsupported regex-based removeParam: /cUrl|ref/ - Unsupported regex-based removeParam: /topicPageSponsorship|^itm_/ - Unsupported regex-based removeParam: /^utm_/ - Unsupported regex-based removeParam: /^trk/ - Unsupported regex-based removeParam: /^utm_cid/ - Unsupported regex-based removeParam: /entries/ - Unsupported regex-based removeParam: /Version/ - Unsupported regex-based removeParam: /^at_custom/ - Unsupported regex-based removeParam: /mcorgid|mid|ts/ - Unsupported regex-based removeParam: /^dc_trk_/ - Unsupported regex-based removeParam: /^(ppref|ref|pid)=/ - Unsupported regex-based removeParam: /^subid/ - Unsupported regex-based removeParam: /^(_requestid|reff)=/ - Unsupported regex-based removeParam: /^affExtParam/ - Unsupported regex-based removeParam: /^otracker/ - Unsupported regex-based removeParam: /spm=|scm=|from=|keyori=|sugg=|search=|mp=|c=|^abtest|^abbucket|pos=|themeID=|algArgs=|clickTrackInfo=|acm=|item_id=|version=|up_id=|pvid=/ - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported modifier exception - Unsupported regex-based removeParam: /^\/_ui\/desktop\/common\/js\/uiAnalytics\// - Unsupported regex-based removeParam: /_ui\/shared\/common\/js\/analytics\/with-intersection-track.js/ - Unsupported regex-based removeParam: /_ui\/shared\/common\/js\/InappCommunicationManager.js/ - Unsupported regex-based removeParam: /_ui\/shared\/common\/js\/util\/jquery.analytics-utils.js/ - Unsupported regex-based removeParam: /^(device|country|path)=/ - Unsupported regex-based removeParam: /cdt|ref/ - Unsupported regex-based removeParam: ~/^(primer|subset_id)=/ - Unsupported regex-based removeParam: /tour|campaign/ - Unsupported modifier exception -CSS-specific: 1 distinct filters - Combined into 3 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'annoyances-cookies': - Fetching remote https://ublockorigin.github.io/uAssets/thirdparties/easylist-cookies.txt - Fetching remote https://ublockorigin.github.io/uAssets/filters/annoyances-cookies.txt -Input filter count: 2000 - Accepted filter count: 1997 - Rejected filter count: 0 -Output rule count: 1691 - Plain good: 1690 - - Maybe good (regexes): 1 - redirect=: 0 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 0 - -CSS-generic: 16939 plain CSS selectors -CSS-generic-high: 351 plain CSS selectors -CSS-specific: 5385 distinct filters - Combined into 16378 distinct hostnames - Combined into 1 distinct entities -CSS-declarative: 66 distinct filters - Combined into 5469 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 7 distinct combined selectors - Combined into 17 distinct hostnames - Combined into 0 distinct entities -============================ -Listset for 'annoyances-overlays': - Fetching remote https://filters.adtidy.org/extension/ublock/filters/19.txt - Fetching remote https://ublockorigin.github.io/uAssets/filters/annoyances-others.txt -Input filter count: 2483 - Accepted filter count: 2481 - Rejected filter count: 0 -Output rule count: 1520 - Pruning requestDomains: from 530 to 529 - Plain good: 1454 - - Maybe good (regexes): 3 - redirect=: 52 - removeparams= (accepted/discarded): 1/0 - modifyHeaders=: 6 - Unsupported: 4 - Can't salvage rule with only entity-based domain= option: gmx.* - regexFilter is not RE2-compatible: ^https:\/\/[0-9a-z]{7,25}\.com\/v2(?:\/0\/)?(?=[0-9a-z_-]{0,84}[A-Z])(?=[a-zA-Z_-]{0,84}[0-9])[0-9a-zA-Z_-]{54,85}(#\?v=[0-9a-f]{32})?$ - regexFilter is not RE2-compatible: ^https:\/\/[0-9a-z]{7,25}\.com\/v2(?:\/0\/)?(?=[0-9a-z_-]{0,84}[A-Z])(?=[a-zA-Z_-]{0,84}[0-9])[0-9a-zA-Z_-]{54,85}(#\?v=[0-9a-f]{32})?$ - regexFilter is not RE2-compatible: ^https:\/\/[0-9a-z]{7,25}\.com\/v2(?:\/0\/)?(?=[0-9a-z_-]{0,84}[A-Z])(?=[a-zA-Z_-]{0,84}[0-9])[0-9a-zA-Z_-]{54,85}(#\?v=[0-9a-f]{32})?$ -CSS-generic: 35 plain CSS selectors -CSS-generic-high: 3 plain CSS selectors -CSS-specific: 10701 distinct filters - Combined into 10527 distinct hostnames - Combined into 68 distinct entities -CSS-declarative: 610 distinct filters - Combined into 2227 distinct hostnames - Combined into 25 distinct entities -Procedural-related distinct filters: 377 distinct combined selectors - Combined into 758 distinct hostnames - Combined into 7 distinct entities -============================ -Listset for 'annoyances-social': - Fetching remote https://filters.adtidy.org/extension/ublock/filters/4.txt -Input filter count: 643 - Accepted filter count: 643 - Rejected filter count: 0 -Output rule count: 544 - Plain good: 541 - - Maybe good (regexes): 0 - redirect=: 1 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 2 - regexFilter is not RE2-compatible: \/icons_addtoany\/(?!a2a|bookmark|print)[a-z]+ - Can't salvage rule with only entity-based domain= option: freelancer.* -CSS-generic: 753 plain CSS selectors -CSS-generic-high: 86 plain CSS selectors -CSS-specific: 10807 distinct filters - Combined into 11984 distinct hostnames - Combined into 63 distinct entities -CSS-declarative: 115 distinct filters - Combined into 204 distinct hostnames - Combined into 7 distinct entities -Procedural-related distinct filters: 514 distinct combined selectors - Combined into 563 distinct hostnames - Combined into 4 distinct entities -============================ -Listset for 'annoyances-widgets': - Fetching remote https://filters.adtidy.org/extension/ublock/filters/22.txt -Input filter count: 665 - Accepted filter count: 665 - Rejected filter count: 0 -Output rule count: 432 - Plain good: 432 - - Maybe good (regexes): 0 - redirect=: 0 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 0 - -CSS-generic: 25 plain CSS selectors -CSS-generic-high: 7 plain CSS selectors -CSS-specific: 1014 distinct filters - Combined into 981 distinct hostnames - Combined into 2 distinct entities -CSS-declarative: 15 distinct filters - Combined into 14 distinct hostnames - Combined into 0 distinct entities -Procedural-related distinct filters: 73 distinct combined selectors - Combined into 54 distinct hostnames - Combined into 1 distinct entities -============================ -Listset for 'annoyances-others': - Fetching remote https://filters.adtidy.org/extension/ublock/filters/21.txt -Input filter count: 427 - Accepted filter count: 427 - Rejected filter count: 0 -Output rule count: 398 - Plain good: 393 - - Maybe good (regexes): 2 - redirect=: 1 - removeparams= (accepted/discarded): 2/0 - modifyHeaders=: 0 - Unsupported: 0 - -CSS-generic: 6 plain CSS selectors -CSS-specific: 3598 distinct filters - Combined into 3352 distinct hostnames - Combined into 33 distinct entities -CSS-declarative: 391 distinct filters - Combined into 937 distinct hostnames - Combined into 5 distinct entities -Procedural-related distinct filters: 169 distinct combined selectors - Combined into 144 distinct hostnames - Combined into 3 distinct entities -============================ -Listset for 'stevenblack-hosts': - Fetching remote https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts -Input filter count: 210426 - Accepted filter count: 210426 - Rejected filter count: 0 -Output rule count: 1 - Pruning requestDomains: from 210426 to 108459 - Plain good: 1 - - Maybe good (regexes): 0 - redirect=: 0 - removeparams= (accepted/discarded): 0/0 - modifyHeaders=: 0 - Unsupported: 0 - diff --git a/dist/version b/dist/version index 33894b4bb88e9..08ceb89e82319 100644 --- a/dist/version +++ b/dist/version @@ -1 +1 @@ -1.58.1.3 \ No newline at end of file +1.61.3.9 \ No newline at end of file diff --git a/platform/chromium/manifest.json b/platform/chromium/manifest.json index 637b26764bcdc..ba860b6e36bd7 100644 --- a/platform/chromium/manifest.json +++ b/platform/chromium/manifest.json @@ -89,7 +89,7 @@ }, "incognito": "split", "manifest_version": 2, - "minimum_chrome_version": "73.0", + "minimum_chrome_version": "80.0", "name": "uBlock Origin", "options_ui": { "page": "dashboard.html", diff --git a/platform/chromium/vapi-background-ext.js b/platform/chromium/vapi-background-ext.js index 29de305846647..acbdc3e9d7b74 100644 --- a/platform/chromium/vapi-background-ext.js +++ b/platform/chromium/vapi-background-ext.js @@ -19,10 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -/* globals browser */ - -'use strict'; - /******************************************************************************/ // https://github.com/uBlockOrigin/uBlock-issues/issues/1659 @@ -90,71 +86,47 @@ vAPI.Tabs = class extends vAPI.Tabs { ['gif','image'],['ico','image'],['jpeg','image'],['jpg','image'],['png','image'],['webp','image'] ]); - const headerValue = (headers, name) => { - let i = headers.length; - while ( i-- ) { - if ( headers[i].name.toLowerCase() === name ) { - return headers[i].value.trim(); - } - } - return ''; - }; - const parsedURL = new URL('https://www.example.org/'); - // Extend base class to normalize as per platform. + // Extend base class to normalize as per platform vAPI.Net = class extends vAPI.Net { normalizeDetails(details) { // Chromium 63+ supports the `initiator` property, which contains - // the URL of the origin from which the network request was made. - if ( - typeof details.initiator === 'string' && - details.initiator !== 'null' - ) { + // the URL of the origin from which the network request was made + if ( details.initiator && details.initiator !== 'null' ) { details.documentUrl = details.initiator; } - - let type = details.type; - + const type = details.type; if ( type === 'imageset' ) { details.type = 'image'; return; } - - // The rest of the function code is to normalize type if ( type !== 'other' ) { return; } - - // Try to map known "extension" part of URL to request type. - parsedURL.href = details.url; - const path = parsedURL.pathname, - pos = path.indexOf('.', path.length - 6); - if ( pos !== -1 && (type = extToTypeMap.get(path.slice(pos + 1))) ) { - details.type = type; + // Try to map known "extension" part of URL to request type + if ( details.responseHeaders === undefined ) { + parsedURL.href = details.url; + const path = parsedURL.pathname; + const pos = path.indexOf('.', path.length - 6); + if ( pos !== -1 ) { + details.type = extToTypeMap.get(path.slice(pos + 1)) || type; + } return; } - - // Try to extract type from response headers if present. - if ( details.responseHeaders ) { - type = headerValue(details.responseHeaders, 'content-type'); - if ( type.startsWith('font/') ) { - details.type = 'font'; - return; - } - if ( type.startsWith('image/') ) { - details.type = 'image'; - return; - } - if ( type.startsWith('audio/') || type.startsWith('video/') ) { - details.type = 'media'; - return; - } + // Try to extract type from response headers + const ctype = this.headerValue(details.responseHeaders, 'content-type'); + if ( ctype.startsWith('font/') ) { + details.type = 'font'; + } else if ( ctype.startsWith('image/') ) { + details.type = 'image'; + } else if ( ctype.startsWith('audio/') || ctype.startsWith('video/') ) { + details.type = 'media'; } } // https://www.reddit.com/r/uBlockOrigin/comments/9vcrk3/ // Some types can be mapped from 'other', thus include 'other' if and - // only if the caller is interested in at least one of those types. + // only if the caller is interested in at least one of those types denormalizeTypes(types) { if ( types.length === 0 ) { return Array.from(this.validTypes); @@ -236,19 +208,43 @@ vAPI.prefetching = (( ) => { /******************************************************************************/ -vAPI.scriptletsInjector = ((doc, details) => { - let script; - try { - script = doc.createElement('script'); - script.appendChild(doc.createTextNode(details.scriptlets)); - (doc.head || doc.documentElement).appendChild(script); - self.uBO_scriptletsInjected = details.filters; - } catch (ex) { - } - if ( script ) { - script.remove(); - script.textContent = ''; - } -}).toString(); +vAPI.scriptletsInjector = (( ) => { + const parts = [ + '(', + function(details) { + if ( typeof self.uBO_scriptletsInjected === 'string' ) { return; } + const doc = document; + const { location } = doc; + if ( location === null ) { return; } + const { hostname } = location; + if ( hostname !== '' && details.hostname !== hostname ) { return; } + let script; + try { + script = doc.createElement('script'); + script.appendChild(doc.createTextNode(details.scriptlets)); + (doc.head || doc.documentElement).appendChild(script); + self.uBO_scriptletsInjected = details.filters; + } catch (ex) { + } + if ( script ) { + script.remove(); + script.textContent = ''; + } + return 0; + }.toString(), + ')(', + 'json-slot', + ');', + ]; + const jsonSlot = parts.indexOf('json-slot'); + return (hostname, details) => { + parts[jsonSlot] = JSON.stringify({ + hostname, + scriptlets: details.mainWorld, + filters: details.filters, + }); + return parts.join(''); + }; +})(); /******************************************************************************/ diff --git a/platform/common/vapi-background.js b/platform/common/vapi-background.js index 283ffe6efd275..fac5121c00082 100644 --- a/platform/common/vapi-background.js +++ b/platform/common/vapi-background.js @@ -958,6 +958,7 @@ vAPI.messaging = { onPortDisconnect: function(port) { this.ports.delete(port.name); + void browser.runtime.lastError; }, // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/Port @@ -1381,6 +1382,14 @@ vAPI.Net = class { if ( this.suspendDepth !== 0 ) { return; } this.unsuspendAllRequests(discard); } + headerValue(headers, name) { + for ( const header of headers ) { + if ( header.name.toLowerCase() === name ) { + return header.value.trim(); + } + } + return ''; + } static canSuspend() { return false; } diff --git a/platform/common/vapi-common.js b/platform/common/vapi-common.js index b2b047bc05a8b..1cf98242f3449 100644 --- a/platform/common/vapi-common.js +++ b/platform/common/vapi-common.js @@ -163,6 +163,7 @@ vAPI.webextFlavor = { // This is always true. soup.add('ublock').add('webext'); + soup.add('ipaddress'); // Whether this is a dev build. if ( /^\d+\.\d+\.\d+\D/.test(browser.runtime.getManifest().version) ) { diff --git a/platform/firefox/manifest.json b/platform/firefox/manifest.json index aa49d395a9291..bd347e5eeadd8 100644 --- a/platform/firefox/manifest.json +++ b/platform/firefox/manifest.json @@ -99,7 +99,8 @@ "32": "img/ublock.svg", "48": "img/ublock.svg", "64": "img/ublock.svg", - "96": "img/ublock.svg" + "96": "img/ublock.svg", + "128": "img/ublock.svg" }, "manifest_version": 2, "name": "uBlock Origin", diff --git a/platform/firefox/vapi-background-ext.js b/platform/firefox/vapi-background-ext.js index 8ecefc9a8e197..5710224a34adb 100644 --- a/platform/firefox/vapi-background-ext.js +++ b/platform/firefox/vapi-background-ext.js @@ -19,12 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -/* globals browser */ - -'use strict'; - -/******************************************************************************/ - import { domainFromHostname, hostnameFromNetworkURL, @@ -32,26 +26,20 @@ import { /******************************************************************************/ -// Canonical name-uncloaking feature. -let cnameUncloakEnabled = browser.dns instanceof Object; -let cnameUncloakProxied = false; - -// https://github.com/uBlockOrigin/uBlock-issues/issues/911 -// We detect here whether network requests are proxied, and if so, -// de-aliasing of hostnames will be disabled to avoid possible -// DNS leaks. -const proxyDetector = function(details) { - if ( details.proxyInfo instanceof Object ) { - cnameUncloakEnabled = false; - proxyDetectorTryCount = 0; - } - if ( proxyDetectorTryCount === 0 ) { - browser.webRequest.onHeadersReceived.removeListener(proxyDetector); - return; +const dnsAPI = browser.dns || { + resolve() { + return Promise.resolve(); } - proxyDetectorTryCount -= 1; }; -let proxyDetectorTryCount = 0; + +const isPromise = o => o instanceof Promise; +const isResolvedObject = o => o instanceof Object && + o instanceof Promise === false; +const reIPv4 = /^\d+\.\d+\.\d+\.\d+$/ +const skipDNS = proxyInfo => + proxyInfo && (proxyInfo.proxyDNS || proxyInfo.type?.charCodeAt(0) === 0x68 /* h */); + +/******************************************************************************/ // Related issues: // - https://github.com/gorhill/uBlock/issues/1327 @@ -64,26 +52,27 @@ vAPI.Net = class extends vAPI.Net { constructor() { super(); this.pendingRequests = []; - this.canUncloakCnames = browser.dns instanceof Object; - this.cnames = new Map([ [ '', null ] ]); + this.dnsList = []; // ring buffer + this.dnsWritePtr = 0; // next write pointer in ring buffer + this.dnsMaxCount = 512; // max size of ring buffer + this.dnsDict = new Map(); // hn to index in ring buffer + this.dnsCacheTTL = 600; // TTL in seconds + this.canUncloakCnames = true; + this.cnameUncloakEnabled = true; this.cnameIgnoreList = null; this.cnameIgnore1stParty = true; this.cnameIgnoreExceptions = true; this.cnameIgnoreRootDocument = true; - this.cnameMaxTTL = 120; this.cnameReplayFullURL = false; - this.cnameFlushTime = Date.now() + this.cnameMaxTTL * 60000; + this.dnsResolveEnabled = true; } + setOptions(options) { super.setOptions(options); if ( 'cnameUncloakEnabled' in options ) { - cnameUncloakEnabled = - this.canUncloakCnames && + this.cnameUncloakEnabled = options.cnameUncloakEnabled !== false; } - if ( 'cnameUncloakProxied' in options ) { - cnameUncloakProxied = options.cnameUncloakProxied === true; - } if ( 'cnameIgnoreList' in options ) { this.cnameIgnoreList = this.regexFromStrList(options.cnameIgnoreList); @@ -100,54 +89,41 @@ vAPI.Net = class extends vAPI.Net { this.cnameIgnoreRootDocument = options.cnameIgnoreRootDocument !== false; } - if ( 'cnameMaxTTL' in options ) { - this.cnameMaxTTL = options.cnameMaxTTL || 120; - } if ( 'cnameReplayFullURL' in options ) { this.cnameReplayFullURL = options.cnameReplayFullURL === true; } - this.cnames.clear(); this.cnames.set('', null); - this.cnameFlushTime = Date.now() + this.cnameMaxTTL * 60000; - // https://github.com/uBlockOrigin/uBlock-issues/issues/911 - // Install/remove proxy detector. - if ( vAPI.webextFlavor.major < 80 ) { - const wrohr = browser.webRequest.onHeadersReceived; - if ( cnameUncloakEnabled === false || cnameUncloakProxied ) { - if ( wrohr.hasListener(proxyDetector) ) { - wrohr.removeListener(proxyDetector); - } - } else if ( wrohr.hasListener(proxyDetector) === false ) { - wrohr.addListener( - proxyDetector, - { urls: [ '*://*/*' ] }, - [ 'blocking' ] - ); - } - proxyDetectorTryCount = 32; + if ( 'dnsCacheTTL' in options ) { + this.dnsCacheTTL = options.dnsCacheTTL; + } + if ( 'dnsResolveEnabled' in options ) { + this.dnsResolveEnabled = options.dnsResolveEnabled === true; } + this.dnsList.fill(null); + this.dnsDict.clear(); } + normalizeDetails(details) { + // https://github.com/uBlockOrigin/uBlock-issues/issues/3379 + if ( skipDNS(details.proxyInfo) && details.ip === '0.0.0.0' ) { + details.ip = null; + } const type = details.type; - if ( type === 'imageset' ) { details.type = 'image'; return; } - + if ( type !== 'object' ) { return; } + // Try to extract type from response headers if present. + if ( details.responseHeaders === undefined ) { return; } + const ctype = this.headerValue(details.responseHeaders, 'content-type'); // https://github.com/uBlockOrigin/uBlock-issues/issues/345 // Re-categorize an embedded object as a `sub_frame` if its // content type is that of a HTML document. - if ( type === 'object' && Array.isArray(details.responseHeaders) ) { - for ( const header of details.responseHeaders ) { - if ( header.name.toLowerCase() === 'content-type' ) { - if ( header.value.startsWith('text/html') ) { - details.type = 'sub_frame'; - } - break; - } - } + if ( ctype === 'text/html' ) { + details.type = 'sub_frame'; } } + denormalizeTypes(types) { if ( types.length === 0 ) { return Array.from(this.validTypes); @@ -166,77 +142,21 @@ vAPI.Net = class extends vAPI.Net { } return Array.from(out); } + canonicalNameFromHostname(hn) { - const cnRecord = this.cnames.get(hn); - if ( cnRecord !== undefined && cnRecord !== null ) { - return cnRecord.cname; - } - } - processCanonicalName(hn, cnRecord, details) { - if ( cnRecord === null ) { return; } - if ( cnRecord.isRootDocument ) { return; } - const hnBeg = details.url.indexOf(hn); - if ( hnBeg === -1 ) { return; } - const oldURL = details.url; - let newURL = oldURL.slice(0, hnBeg) + cnRecord.cname; - const hnEnd = hnBeg + hn.length; - if ( this.cnameReplayFullURL ) { - newURL += oldURL.slice(hnEnd); - } else { - const pathBeg = oldURL.indexOf('/', hnEnd); - if ( pathBeg !== -1 ) { - newURL += oldURL.slice(hnEnd, pathBeg + 1); - } - } - details.url = newURL; - details.aliasURL = oldURL; - return super.onBeforeSuspendableRequest(details); - } - recordCanonicalName(hn, record, isRootDocument) { - if ( (this.cnames.size & 0b111111) === 0 ) { - const now = Date.now(); - if ( now >= this.cnameFlushTime ) { - this.cnames.clear(); this.cnames.set('', null); - this.cnameFlushTime = now + this.cnameMaxTTL * 60000; - } - } - let cname = - typeof record.canonicalName === 'string' && - record.canonicalName !== hn - ? record.canonicalName - : ''; - if ( - cname !== '' && - this.cnameIgnore1stParty && - domainFromHostname(cname) === domainFromHostname(hn) - ) { - cname = ''; - } - if ( - cname !== '' && - this.cnameIgnoreList !== null && - this.cnameIgnoreList.test(cname) - ) { - cname = ''; - } - const cnRecord = cname !== '' ? { cname, isRootDocument } : null; - this.cnames.set(hn, cnRecord); - return cnRecord; + if ( hn === '' ) { return; } + const dnsEntry = this.dnsFromCache(hn, true); + if ( isResolvedObject(dnsEntry) === false ) { return; } + return dnsEntry.cname; } + regexFromStrList(list) { - if ( - typeof list !== 'string' || - list.length === 0 || - list === 'unset' || - browser.dns instanceof Object === false - ) { + if ( typeof list !== 'string' || list.length === 0 || list === 'unset' ) { return null; } - if ( list === '*' ) { - return /^./; - } + if ( list === '*' ) { return /^./; } return new RegExp( - '(?:^|\.)(?:' + + '(?:^|\\.)(?:' + list.trim() .split(/\s+/) .map(a => a.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) @@ -244,9 +164,14 @@ vAPI.Net = class extends vAPI.Net { ')$' ); } + onBeforeSuspendableRequest(details) { + const hn = hostnameFromNetworkURL(details.url); + const dnsEntry = this.dnsFromCache(hn); + if ( isResolvedObject(dnsEntry) && dnsEntry.ip ) { + details.ip = dnsEntry.ip; + } const r = super.onBeforeSuspendableRequest(details); - if ( cnameUncloakEnabled === false ) { return r; } if ( r !== undefined ) { if ( r.cancel === true || @@ -256,24 +181,144 @@ vAPI.Net = class extends vAPI.Net { return r; } } - const hn = hostnameFromNetworkURL(details.url); - const cnRecord = this.cnames.get(hn); - if ( cnRecord !== undefined ) { - return this.processCanonicalName(hn, cnRecord, details); + if ( isResolvedObject(dnsEntry) ) { + return this.onAfterDNSResolution(hn, details, dnsEntry); + } + if ( skipDNS(details.proxyInfo) ) { return; } + if ( this.dnsShouldResolve(hn) === false ) { return; } + const promise = dnsEntry || this.dnsResolve(hn, details); + return promise.then(( ) => this.onAfterDNSResolution(hn, details)); + } + + onAfterDNSResolution(hn, details, dnsEntry) { + if ( dnsEntry === undefined ) { + dnsEntry = this.dnsFromCache(hn); + if ( isResolvedObject(dnsEntry) === false ) { return; } + } + let proceed = false; + if ( dnsEntry.cname && this.cnameUncloakEnabled ) { + const newURL = this.uncloakURL(hn, dnsEntry, details); + if ( newURL ) { + details.aliasURL = details.url; + details.url = newURL; + proceed = true; + } } - const documentUrl = details.documentUrl || details.url; - const isRootDocument = this.cnameIgnoreRootDocument && - hn === hostnameFromNetworkURL(documentUrl); - return browser.dns.resolve(hn, [ 'canonical_name' ]).then( - rec => { - const cnRecord = this.recordCanonicalName(hn, rec, isRootDocument); - return this.processCanonicalName(hn, cnRecord, details); - }, - ( ) => { - this.cnames.set(hn, null); + if ( dnsEntry.ip && details.ip !== dnsEntry.ip ) { + details.ip = dnsEntry.ip + proceed = true; + } + if ( proceed === false ) { return; } + // Must call method on base class + return super.onBeforeSuspendableRequest(details); + } + + dnsToCache(hn, record, details) { + const dnsEntry = { hn, until: Date.now() + this.dnsCacheTTL * 1000 }; + if ( record ) { + const cname = this.cnameFromRecord(hn, record, details); + if ( cname ) { dnsEntry.cname = cname; } + const ip = this.ipFromRecord(record); + if ( ip ) { dnsEntry.ip = ip; } + } + this.dnsSetCache(-1, hn, dnsEntry); + return dnsEntry; + } + + dnsFromCache(hn, passive = false) { + const i = this.dnsDict.get(hn); + if ( i === undefined ) { return; } + if ( isPromise(i) ) { return i; } + const dnsEntry = this.dnsList[i]; + if ( dnsEntry !== null && dnsEntry.hn === hn ) { + if ( passive || dnsEntry.until >= Date.now() ) { + return dnsEntry; + } + } + this.dnsSetCache(i); + } + + dnsSetCache(i, hn, after) { + if ( i < 0 ) { + const j = this.dnsDict.get(hn); + if ( typeof j === 'number' ) { + this.dnsList[j] = after; + return; } + i = this.dnsWritePtr++; + this.dnsWritePtr %= this.dnsMaxCount; + } + const before = this.dnsList[i]; + if ( before ) { + this.dnsDict.delete(before.hn); + } + if ( after ) { + this.dnsDict.set(hn, i); + this.dnsList[i] = after; + } else { + if ( hn ) { this.dnsDict.delete(hn); } + this.dnsList[i] = null; + } + } + + dnsShouldResolve(hn) { + if ( this.dnsResolveEnabled === false ) { return false; } + if ( hn === '' ) { return false; } + const c0 = hn.charCodeAt(0); + if ( c0 === 0x5B /* [ */ ) { return false; } + if ( c0 > 0x39 /* 9 */ ) { return true; } + return reIPv4.test(hn) === false; + } + + dnsResolve(hn, details) { + const promise = dnsAPI.resolve(hn, [ 'canonical_name' ]).then( + rec => this.dnsToCache(hn, rec, details), + ( ) => this.dnsToCache(hn) ); + this.dnsDict.set(hn, promise); + return promise; + } + + cnameFromRecord(hn, record, details) { + const cn = record.canonicalName; + if ( cn === undefined ) { return; } + if ( cn === hn ) { return; } + if ( this.cnameIgnore1stParty ) { + if ( domainFromHostname(cn) === domainFromHostname(hn) ) { return; } + } + if ( this.cnameIgnoreList !== null ) { + if ( this.cnameIgnoreList.test(cn) === false ) { return; } + } + if ( this.cnameIgnoreRootDocument ) { + const origin = hostnameFromNetworkURL(details.documentUrl || details.url); + if ( hn === origin ) { return; } + } + return cn; } + + uncloakURL(hn, dnsEntry, details) { + const hnBeg = details.url.indexOf(hn); + if ( hnBeg === -1 ) { return; } + const oldURL = details.url; + const newURL = oldURL.slice(0, hnBeg) + dnsEntry.cname; + const hnEnd = hnBeg + hn.length; + if ( this.cnameReplayFullURL ) { + return newURL + oldURL.slice(hnEnd); + } + const pathBeg = oldURL.indexOf('/', hnEnd); + if ( pathBeg !== -1 ) { + return newURL + oldURL.slice(hnEnd, pathBeg + 1); + } + return newURL; + } + + ipFromRecord(record) { + const { addresses } = record; + if ( Array.isArray(addresses) === false ) { return; } + if ( addresses.length === 0 ) { return; } + return addresses.join('\n'); + } + suspendOneRequest(details) { const pending = { details: Object.assign({}, details), @@ -286,6 +331,7 @@ vAPI.Net = class extends vAPI.Net { this.pendingRequests.push(pending); return pending.promise; } + unsuspendAllRequests(discard = false) { const pendingRequests = this.pendingRequests; this.pendingRequests = []; @@ -297,6 +343,7 @@ vAPI.Net = class extends vAPI.Net { ); } } + static canSuspend() { return true; } @@ -304,25 +351,77 @@ vAPI.Net = class extends vAPI.Net { /******************************************************************************/ -vAPI.scriptletsInjector = ((doc, details) => { - let script, url; - try { - const blob = new self.Blob( - [ details.scriptlets ], - { type: 'text/javascript; charset=utf-8' } - ); - url = self.URL.createObjectURL(blob); - script = doc.createElement('script'); - script.async = false; - script.src = url; - (doc.head || doc.documentElement || doc).append(script); - self.uBO_scriptletsInjected = details.filters; - } catch (ex) { - } - if ( url ) { - if ( script ) { script.remove(); } - self.URL.revokeObjectURL(url); - } -}).toString(); +vAPI.scriptletsInjector = (( ) => { + const parts = [ + '(', + function(details) { + if ( typeof self.uBO_scriptletsInjected === 'string' ) { return; } + const doc = document; + const { location } = doc; + if ( location === null ) { return; } + const { hostname } = location; + if ( hostname !== '' && details.hostname !== hostname ) { return; } + // Use a page world sentinel to verify that execution was + // successful + const { sentinel } = details; + let script; + try { + const code = [ + `self['${sentinel}'] = true;`, + details.scriptlets, + ].join('\n'); + script = doc.createElement('script'); + script.appendChild(doc.createTextNode(code)); + (doc.head || doc.documentElement).appendChild(script); + } catch (ex) { + } + if ( script ) { + script.remove(); + script.textContent = ''; + script = undefined; + } + if ( self.wrappedJSObject[sentinel] ) { + delete self.wrappedJSObject[sentinel]; + self.uBO_scriptletsInjected = details.filters; + return 0; + } + // https://github.com/uBlockOrigin/uBlock-issues/issues/235 + // Fall back to blob injection if execution through direct + // injection failed + let url; + try { + const blob = new self.Blob( + [ details.scriptlets ], + { type: 'text/javascript; charset=utf-8' } + ); + url = self.URL.createObjectURL(blob); + script = doc.createElement('script'); + script.async = false; + script.src = url; + (doc.head || doc.documentElement || doc).append(script); + self.uBO_scriptletsInjected = details.filters; + } catch (ex) { + } + if ( url ) { + if ( script ) { script.remove(); } + self.URL.revokeObjectURL(url); + } + return 0; + }.toString(), + ')(', + 'json-slot', + ');', + ]; + const jsonSlot = parts.indexOf('json-slot'); + return (hostname, details) => { + parts[jsonSlot] = JSON.stringify({ + hostname, + scriptlets: details.mainWorld, + filters: details.filters, + sentinel: vAPI.generateSecret(3), + }); + return parts.join(''); + }; +})(); /******************************************************************************/ diff --git a/platform/mv3/README.md b/platform/mv3/README.md index 2400bfe71cffa..28f0bdab2a395 100644 --- a/platform/mv3/README.md +++ b/platform/mv3/README.md @@ -15,7 +15,7 @@ Upon completion of the script, the resulting extension package will become prese - Chromium: `dist/build/uBOLite.chromium` - Firefox: `dist/build/uBOLite.firefox` -The folder `dist/build/mv3-data` will cache data fetched from remote server, so as to avoid fetching repeatedly from remote server with repeated build commands. Remove `dist/build/mv3-data` if you want to build with latest versions of filter lists. +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. diff --git a/platform/mv3/chromium/manifest.json b/platform/mv3/chromium/manifest.json index b3e77ccc24ab5..72760301c5a32 100644 --- a/platform/mv3/chromium/manifest.json +++ b/platform/mv3/chromium/manifest.json @@ -25,7 +25,7 @@ "128": "img/icon_128.png" }, "manifest_version": 3, - "minimum_chrome_version": "118.0", + "minimum_chrome_version": "122.0", "name": "__MSG_extName__", "options_page": "dashboard.html", "optional_host_permissions": [ @@ -41,6 +41,5 @@ "storage": { "managed_schema": "managed_storage.json" }, - "version": "1.0", - "web_accessible_resources": [] + "version": "1.0" } diff --git a/platform/mv3/description/webstore.ar.txt b/platform/mv3/description/webstore.ar.txt index 97675121f0c9d..9053a997ad161 100644 --- a/platform/mv3/description/webstore.ar.txt +++ b/platform/mv3/description/webstore.ar.txt @@ -7,7 +7,7 @@ - الخصوصية السهلة - قائمة خادم الإعلانات والتتبع لبيتر لوي -يمكنك إضافة المزيد من القواعد من خلال زيارة صفحة الخيارات ومن ثم أنقر على رمز _Cogs_ في اللوحة المنبثقة. +يمكنك تفعيل المزيد من مجموعات القواعد من خلال زيارة صفحة الخيارات - انقر على أيقونة _الترس_ في لوحة الإشعارات. uBOL صريح تمامًا، مما يعني أنه لا تحتاج إلى uBOL بشكل دائم لحدوث تصفية المحتوى، يتم إجراء تصفية المحتوى من خلال إضافة CSS/JS بشكل موثوق به بواسطة المتصفح نفسه بدلًا من الإضافة. هذا يعني أن uBOL نفسه لا يستهلك موارد وحدة المعالجة المركزية/الذاكرة أثناء استمراره في حظر المحتوى. عملية عامل الخدمة في uBOL مطلوبة _فقط_ عند التفاعل مع اللوحة المنبثقة أو صفحة الخيارات. diff --git a/platform/mv3/description/webstore.az.txt b/platform/mv3/description/webstore.az.txt index 8ff852cf786a6..61d4f83dca739 100644 --- a/platform/mv3/description/webstore.az.txt +++ b/platform/mv3/description/webstore.az.txt @@ -7,7 +7,7 @@ Defolt qaydalar dəsti uBlock Origin-in defolt filtr dəstinə uyğundur: - EasyPrivacy - Peter Lowe-un Reklam və izləyici server siyahısı -You can add more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. +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. diff --git a/platform/mv3/description/webstore.be.txt b/platform/mv3/description/webstore.be.txt index d5a2e9812c0df..d9749c59cca75 100644 --- a/platform/mv3/description/webstore.be.txt +++ b/platform/mv3/description/webstore.be.txt @@ -1,13 +1,13 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Лайт (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 add more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. +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. diff --git a/platform/mv3/description/webstore.bg.txt b/platform/mv3/description/webstore.bg.txt index 6e58550d3cf46..3430ca651326e 100644 --- a/platform/mv3/description/webstore.bg.txt +++ b/platform/mv3/description/webstore.bg.txt @@ -7,7 +7,7 @@ uBO Lite (uBOL) е блокер за съдържание *без разреше - EasyPrivacy - Списък със сървъри на Peter Lowe за реклами и проследяване -Можете да добавите още набори от правила, като посетите страницата с опции – щракнете върху иконата _зъбно колело_ в изскачащия панел. +Можете да включите още набори от правила, като посетите страницата с опции – щракнете върху иконата „зъбно колело“ в изскачащия панел. uBOL е изцяло декларативен, което означава, че няма нужда от постоянен процес на uBOL за филтриране, а филтрирането на съдържание, базирано на инжектиране на CSS/JS, се извършва надеждно от самия браузър, а не от разширението. Това означава, че самият uBOL не консумира ресурси на процесора/паметта, докато тече блокирането на съдържанието – работният процес на услугата на uBOL е необходим _само_ когато взаимодействате с изскачащия панел или страниците с опции. diff --git a/platform/mv3/description/webstore.bn.txt b/platform/mv3/description/webstore.bn.txt index 83e739a19aebb..ba1fcbdc5e9d3 100644 --- a/platform/mv3/description/webstore.bn.txt +++ b/platform/mv3/description/webstore.bn.txt @@ -7,7 +7,7 @@ uBO Lite (uBOL) হল একটি *অনুমতি-হীন* MV3-ভিত - সহজ গোপনীয়তা - পিটার লো এর বিজ্ঞাপন এবং ট্র্যাকিং সার্ভার তালিকা -আপনি অপশন পেজে গিয়ে আরও নিয়ম সেট যোগ করতে পারেন -- পপআপ প্যানেলে _Cogs_ আইকনে ক্লিক করুন। +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-এর পরিষেবার প্রক্রিয়ার প্রয়োজন শুধুমাত্র_ যখন আপনি পপআপ প্যানেল বা অপশন পেজগুলির সাথে ইন্টারঅ্যাক্ট করেন। diff --git a/platform/mv3/description/webstore.br_FR.txt b/platform/mv3/description/webstore.br_FR.txt index 03354935ec791..a768351889f18 100644 --- a/platform/mv3/description/webstore.br_FR.txt +++ b/platform/mv3/description/webstore.br_FR.txt @@ -5,19 +5,19 @@ Ar reolennoù dre ziouer a glot gant silañ dre ziouer uBlock Origin: - Rolloù siloù genidik a uBlock Origin - EasyList - EasyPrivacy -- Peter Lowe’s Ad and tracking server list +- Roll bruderezh ha servijerioù heuliañ Peter Lowe -Tu zo deoc'h ouzhpennañ reolennoù all en arventennoù -- klikit war an ikon _kendentadur_ er banell popup. +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. +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 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. +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 -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. +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. @@ -25,6 +25,6 @@ Gallout a rit termeniñ ar mod silañ dre ziouer e pajenn arventennoù uBOL. Ma Dalc'hit soñj ez eo uBOL ur raktres war ober c'hoazh hag a zo e bal: -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. +- Aotreoù ostiz ledan ebet e-pad ar staliañ -- aotreoù astennet a vez roet splann gant an implijer dre lec'hienn. -- Entirely declarative for reliability and CPU/memory efficiency. +- Disklêriañ penn-da-benn evit ar fiziañs hag an efedusted CPU/memor. diff --git a/platform/mv3/description/webstore.bs.txt b/platform/mv3/description/webstore.bs.txt index 96ba7d2ef9c3b..f0636858a031a 100644 --- a/platform/mv3/description/webstore.bs.txt +++ b/platform/mv3/description/webstore.bs.txt @@ -7,7 +7,7 @@ Zadani skup pravila odgovara zadanom skupu filtera uBlock Origin: - EasyPrivacy - Oglas Peter Lowe i lista servera za praćenje -Možete dodati još skupova pravila tako što ćete posjetiti stranicu sa opcijama -- kliknite na ikonu _Cogs_ na iskačućoj ploči. +You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. 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. diff --git a/platform/mv3/description/webstore.ca.txt b/platform/mv3/description/webstore.ca.txt index e75025530597a..1a5b9cd9aaa45 100644 --- a/platform/mv3/description/webstore.ca.txt +++ b/platform/mv3/description/webstore.ca.txt @@ -7,7 +7,7 @@ El conjunt de regles per defecte correspon al conjunt de filtres per defecte d'u - EasyPrivacy - Llista de servidors de seguiment i anuncis de Peter Lowe -Podeu afegir més conjunts de regles si visiteu la pàgina d'opcions: feu clic a la icona _Cogs_ al tauler emergent. +Podeu habilitar més conjunts de regles si visiteu la pàgina d'opcions: feu clic a la icona _Cogs_ al tauler emergent. 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. diff --git a/platform/mv3/description/webstore.cs.txt b/platform/mv3/description/webstore.cs.txt index 05ca248f754a1..e698d696b48e5 100644 --- a/platform/mv3/description/webstore.cs.txt +++ b/platform/mv3/description/webstore.cs.txt @@ -7,7 +7,7 @@ Výchozí sada pravidel koresponduje k výchozím sadám filtrů uBlock Origin: - EasyPrivacy - Peter Lowe’s Ad and tracking server list -Můžete přidat více sad pravidel navštívením stránky nastavení -- klikněte na ikonu ozubených kol ve vyskakovácím panelu. +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í. diff --git a/platform/mv3/description/webstore.cv.txt b/platform/mv3/description/webstore.cv.txt index e03fa801ee7f0..7669a5939f98c 100644 --- a/platform/mv3/description/webstore.cv.txt +++ b/platform/mv3/description/webstore.cv.txt @@ -7,7 +7,7 @@ The default ruleset corresponds to uBlock Origin's default filterset: - EasyPrivacy - 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. +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. diff --git a/platform/mv3/description/webstore.cy.txt b/platform/mv3/description/webstore.cy.txt index e03fa801ee7f0..dfc59430e5ecf 100644 --- a/platform/mv3/description/webstore.cy.txt +++ b/platform/mv3/description/webstore.cy.txt @@ -1,13 +1,13 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) yw blocwr cynnwys MV3 sy'n gweithredu heb ganiatâd safonol. -The default ruleset corresponds to uBlock Origin's default filterset: +Mae'r set reolau ddiofyn yn cyfateb i set hidlo diofyn uBlock Origin: - uBlock Origin's built-in filter lists - EasyList - EasyPrivacy - 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. +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. diff --git a/platform/mv3/description/webstore.da.txt b/platform/mv3/description/webstore.da.txt index 1d3218873cb5a..34a84077d1281 100644 --- a/platform/mv3/description/webstore.da.txt +++ b/platform/mv3/description/webstore.da.txt @@ -7,7 +7,7 @@ Standardregelsættet svarer til uBlock Origins standardfiltersæt: - EasyPrivacy - Peter Lowe’s Ad and tracking server list -Flere regelsæt kan tilføjes ved at gå til indstillingssiden -- klik på ikonet _Cogs_ i pop op-panelet. +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. diff --git a/platform/mv3/description/webstore.de.txt b/platform/mv3/description/webstore.de.txt index 807ec84c1d918..df224daac5367 100644 --- a/platform/mv3/description/webstore.de.txt +++ b/platform/mv3/description/webstore.de.txt @@ -7,7 +7,7 @@ Die Standardregeln entsprechen den Standardfiltern von uBlock Origin: - EasyPrivacy - Peter Lowe’s Ad and tracking server list -Sie können weitere Regeln hinzufügen, indem Sie die Optionen aufrufen — klicken Sie dazu im Pop-up-Fenster auf das Symbol mit den _Zahnrädern_. +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. diff --git a/platform/mv3/description/webstore.el.txt b/platform/mv3/description/webstore.el.txt index 32d043db89b31..73922f351e7e0 100644 --- a/platform/mv3/description/webstore.el.txt +++ b/platform/mv3/description/webstore.el.txt @@ -1,4 +1,4 @@ -Το uBO Lite (uBOL) είναι ένας blocker περιεχομένου *χωρίς άδειες* που βασίζεται σε MV3. +Το uBO Lite (uBOL) είναι ένα πρόσθετο φραγής περιεχομένου που *δεν απαιτεί δικαιώματα* και βασίζεται στο MV3. Το προεπιλεγμένο σύνολο κανόνων αντιστοιχεί στο προεπιλεγμένο σύνολο φίλτρων του uBlock Origin: @@ -7,7 +7,7 @@ - EasyPrivacy - Peter Lowe’s Ad and tracking server list -Μπορείτε να προσθέσετε περισσότερα σύνολα κανόνων μεταβαίνοντας στη σελίδα επιλογών -- κάντε κλικ στο εικονίδιο _Cogs_ στον αναδυόμενο πίνακα. +Μπορείτε να προσθέσετε περισσότερα σύνολα κανόνων από τη σελίδα επιλογών -- κάντε κλικ στο εικονίδιο _γρανάζι_ στον αναδυόμενο πίνακα. Το uBOL είναι εξ'ολοκλήρου δηλωτικό, πράγμα που σημαίνει ότι δεν υπάρχει ανάγκη για μόνιμη διαδικασία uBOL για να πραγματοποιηθεί το φιλτράρισμα, και το φιλτράρισμα περιεχομένου που βασίζεται σε έγχυση CSS/JS εκτελείται αξιόπιστα από το ίδιο το πρόγραμμα περιήγησης και όχι από την επέκταση. Αυτό σημαίνει ότι το ίδιο το uBOL δεν καταναλώνει πόρους CPU/μνήμης ενώ ο αποκλεισμός περιεχομένου είναι σε εξέλιξη -- η διαδικασία του service worker του uBOL απαιτείται _μόνο_ όταν αλληλεπιδράτε με τον αναδυόμενο πίνακα ή τις σελίδες επιλογών. diff --git a/platform/mv3/description/webstore.en_GB.txt b/platform/mv3/description/webstore.en_GB.txt index e03fa801ee7f0..7669a5939f98c 100644 --- a/platform/mv3/description/webstore.en_GB.txt +++ b/platform/mv3/description/webstore.en_GB.txt @@ -7,7 +7,7 @@ The default ruleset corresponds to uBlock Origin's default filterset: - EasyPrivacy - 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. +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. diff --git a/platform/mv3/description/webstore.eo.txt b/platform/mv3/description/webstore.eo.txt index e03fa801ee7f0..7669a5939f98c 100644 --- a/platform/mv3/description/webstore.eo.txt +++ b/platform/mv3/description/webstore.eo.txt @@ -7,7 +7,7 @@ The default ruleset corresponds to uBlock Origin's default filterset: - EasyPrivacy - 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. +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. diff --git a/platform/mv3/description/webstore.es.txt b/platform/mv3/description/webstore.es.txt index 2ea6cfff29121..e0cbfb8bd4204 100644 --- a/platform/mv3/description/webstore.es.txt +++ b/platform/mv3/description/webstore.es.txt @@ -7,7 +7,7 @@ Por defecto ya trae configuradas las siguientes listas de filtros: - EasyPrivacy - Peter Lowe’s Ad and tracking server list -Puedes añadir más conjuntos de reglas visitando la página de opciones, haz clic en el icono de _engranaje_ del panel emergente. +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. diff --git a/platform/mv3/description/webstore.et.txt b/platform/mv3/description/webstore.et.txt index 520e4ce134edc..0f81da1126305 100644 --- a/platform/mv3/description/webstore.et.txt +++ b/platform/mv3/description/webstore.et.txt @@ -7,7 +7,7 @@ Tavaline reeglitekogum vastab uBlock Origini tavalisele filtritekogumile: - EasyPrivacy Peter Lowe'i reklaamide ja jälitusserverite loend -Reeglitekogumeid saate lisada valikute lehelt ehk avanenud paneelis klõpsake _Cogs_ ikooni. +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. diff --git a/platform/mv3/description/webstore.eu.txt b/platform/mv3/description/webstore.eu.txt index a15101de8214a..c0ebbdfb27e0d 100644 --- a/platform/mv3/description/webstore.eu.txt +++ b/platform/mv3/description/webstore.eu.txt @@ -1,30 +1,30 @@ uBO Lite (uBOL) irakargarri blokeatzailea de, baimen gutxiekin eta MV3ean basatua -The default ruleset corresponds to uBlock Origin's default filterset: +Lehenespenez, iragazki-zerrenda hauek ditu konfiguratuta: UblockOrigin-eko filtro lista -- EasyList +ZerrendaErraza PribazitateaErraza -- Peter Lowe’s Ad and tracking server list +Peter Lowe-ren Ad and tracker zerrenda -You can add more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. +Ruleta gehiago aktibatu ahal duzu aukerak orria --klikatu _Cogs_ ikonoa panelearen lehioan -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 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. -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. +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. -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. +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. -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. +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. -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. +Baimen gehigarrien eskaera onartzen baduzu, oraingo gunean edukiak hobeto iragazi ahal izango ditu. -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. +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. -Keep in mind this is still a work in progress, with these end goals: +Gogoan izan oraindik lan bat dela, azken helburu hauekin: -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. +- Instalatzeko garaian, ez dago baimen zabalik. Erabiltzaileak esplizituki ematen ditu baimen zabalduak. -- Entirely declarative for reliability and CPU/memory efficiency. +- Erabat deklaratiboa fidagarritasunagatik eta CPU/memoriaren eraginkortasunagatik. diff --git a/platform/mv3/description/webstore.fa.txt b/platform/mv3/description/webstore.fa.txt index e03fa801ee7f0..b85b55d27092c 100644 --- a/platform/mv3/description/webstore.fa.txt +++ b/platform/mv3/description/webstore.fa.txt @@ -1,13 +1,13 @@ uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. -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 -You can add more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. +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. diff --git a/platform/mv3/description/webstore.fi.txt b/platform/mv3/description/webstore.fi.txt index 7e5693c715911..672396d3a9f7b 100644 --- a/platform/mv3/description/webstore.fi.txt +++ b/platform/mv3/description/webstore.fi.txt @@ -7,7 +7,7 @@ Oletusarvoiset sääntömääritykset vastaavat uBlock Origin -laajennuksen olet - EasyPrivacy - Peter Lowe’s Ad and tracking server list -Voit lisätä sääntömäärityksiä asetussivulta -- paina ponnahduspaneelin _Rataskuvaketta_. +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ä. @@ -15,7 +15,7 @@ uBOL ei edellytä laajan tietojen luku- ja muokkausoikeuden myöntämistä asenn 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. +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. diff --git a/platform/mv3/description/webstore.fil.txt b/platform/mv3/description/webstore.fil.txt index 0bb5710c6e233..b859f25bf3182 100644 --- a/platform/mv3/description/webstore.fil.txt +++ b/platform/mv3/description/webstore.fil.txt @@ -7,7 +7,7 @@ Tulad ng uBlock Origin, ito rin ang mga default na listahan ng mga filter: - EasyPrivacy - Listahan ni Peter Lowe sa mga ad at tracking server (Peter Lowe’s Ad and tracking server list) -Makakapagdagdag ka ng higit pang mga patakaran sa pahina ng mga opsyon -- pindutin ang icon ng _gulong_ sa popup panel. +You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup 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. diff --git a/platform/mv3/description/webstore.fr.txt b/platform/mv3/description/webstore.fr.txt index 12b9d01d1f4f8..cdf03fc490487 100644 --- a/platform/mv3/description/webstore.fr.txt +++ b/platform/mv3/description/webstore.fr.txt @@ -7,7 +7,7 @@ Les règles par défaut correspondent au filtrage par défaut d'uBlock Origin : - EasyPrivacy - La liste anti-serveurs pub et pistage de Peter Lowe -Vous pouvez ajouter plus de règles en consultant la page des paramètres -- Cliquez sur l'_Engrenage_ dans le panneau pop-up. +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. diff --git a/platform/mv3/description/webstore.fy.txt b/platform/mv3/description/webstore.fy.txt index 63fa94a819b56..2f070096fc3ce 100644 --- a/platform/mv3/description/webstore.fy.txt +++ b/platform/mv3/description/webstore.fy.txt @@ -7,7 +7,7 @@ De standert regelset komt oerien mei de standert filterset fan uBlock Origin: - EasyPrivacy - Peter Lowe’s Ad and tracking-serverlist -Jo kinne mear regelsets tafoegje troch de opsjesside te besykjen – klik op it _tântsjilpiktogram_ yn it pop-uppaniel. +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. diff --git a/platform/mv3/description/webstore.gl.txt b/platform/mv3/description/webstore.gl.txt index a82432f3762c8..6dca35b6e6fbd 100644 --- a/platform/mv3/description/webstore.gl.txt +++ b/platform/mv3/description/webstore.gl.txt @@ -7,7 +7,7 @@ O conxunto de regras predeterminado corresponde ao conxunto de filtros predeterm - EasyPrivacy Lista de servidores de seguimento e anuncios de Peter Lowe -Podes engadir máis conxuntos de regras visitando a páxina de opcións: fai clic na icona _Cogs_ no panel emerxente. +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. diff --git a/platform/mv3/description/webstore.gu.txt b/platform/mv3/description/webstore.gu.txt index e03fa801ee7f0..7669a5939f98c 100644 --- a/platform/mv3/description/webstore.gu.txt +++ b/platform/mv3/description/webstore.gu.txt @@ -7,7 +7,7 @@ The default ruleset corresponds to uBlock Origin's default filterset: - EasyPrivacy - 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. +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. diff --git a/platform/mv3/description/webstore.he.txt b/platform/mv3/description/webstore.he.txt index d931b3dae4271..e9d1100485df9 100644 --- a/platform/mv3/description/webstore.he.txt +++ b/platform/mv3/description/webstore.he.txt @@ -7,7 +7,7 @@ uBO Lite (uBOL) הוא חוסם תוכן *ללא הרשאות* מבוסס MV3. - EasyPrivacy - רשימת שרתי מודעות ומעקב של פיטר לואו -ניתן להוסיף ערכות כללים נוספות מעמוד האפשרויות –על ידי הקשה על סמל _Cogs_ בלוח הצץ. +ניתן לאפשר קבוצות חוקים נוספות בדף האפשרויות - עם לחיצה על סמליל _גלגלי השיניים_ בחלונית הקופצת. uBOL הוא הכרזתי לחלוטין, כלומר אין צורך בתהליך uBOL קבוע כדי שהסינון יתרחש, וסינון תוכן מבוסס הזרקת CSS/JS מבוצע באופן אמין על ידי הדפדפן עצמו ולא על ידי ההרחבה. המשמעות היא ש־uBOL עצמו לא צורכך משאבי מעבד/זיכרון בזמן שחסימת התוכן מתרחשת – תהליך ה־service worker של uBOL נדרש _אך ורק_ בזמן הידוד עם החלון הקופץ או עם עמוד האפשרויות. diff --git a/platform/mv3/description/webstore.hi.txt b/platform/mv3/description/webstore.hi.txt index 7b361bc8c5bed..1f8ba632744af 100644 --- a/platform/mv3/description/webstore.hi.txt +++ b/platform/mv3/description/webstore.hi.txt @@ -7,7 +7,7 @@ uBO Lite (uBOL) एक *अनुमति-रहित* MV3-आधारित - EasyPrivacy - Peter Lowe की विज्ञापन एवं ट्रैकिंग सर्वर सू‍ची -आप विकल्प पृष्ठ पर जाकर और अधिक रूलसेट जोड़ सकते हैं -- पॉपअप पैनल में _Cogs_ आइकन पर क्लिक करें। +आप विकल्प पृष्ठ पर जाकर और अधिक नियम-सेट सक्षम कर सकते हैं -- पॉपअप पैनल में _Cogs_ आइकन पर क्लिक करें। uBOL पूरी तरह से वर्णनात्मक है, जिसका यह अर्थ है कि फ़िल्टरिंग के लिए एक स्थायी uBOL प्रक्रिया की कोई आवश्यकता नहीं है, और CSS/JS इंजेक्शन-आधारित कन्टेन्ट फ़िल्टरिंग एक्सटेंशन के बजाय ब्राउज़र द्वारा विश्वसनीय रूप से की जाती है। इसका यह अर्थ है कि कन्टेन्ट ब्लॉक करते समय uBOL द्वारा सीपीयू/मेमोरी संसाधनों का उपभोग स्वयं नहीं किया जाता है -- uBOL की सर्विस प्रोसेस की आवश्यकता _केवल_ तब होती है जब आप पॉपअप पैनल या विकल्प पृष्ठों पर कोई अंत:क्रिया करते हैं। diff --git a/platform/mv3/description/webstore.hr.txt b/platform/mv3/description/webstore.hr.txt index 898bc2002f3f0..0addfd46d3509 100644 --- a/platform/mv3/description/webstore.hr.txt +++ b/platform/mv3/description/webstore.hr.txt @@ -7,7 +7,7 @@ Zadana lista pravila odgovara uBlock Origin-ovoj zadanoj listi filtera: - EasyPrivacy - Peter Lowe-ova lista oglasa i pratećih servera -Možete dodati više skupova pravila tako što ćete posjetiti stranicu s opcijama -- kliknite ikonu _zupčanika_ na skočnoj ploči. +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. diff --git a/platform/mv3/description/webstore.hu.txt b/platform/mv3/description/webstore.hu.txt index 4d54e2f1f1aa5..bc2d5f2e77fba 100644 --- a/platform/mv3/description/webstore.hu.txt +++ b/platform/mv3/description/webstore.hu.txt @@ -1,4 +1,4 @@ -Az uBO Lite (uBOL) egy *engedélyt nem igénylő* MV3-alapú tartalomblokkoló. +A uBO Lite (uBOL) egy *engedélyt nem igénylő* MV3-alapú tartalomblokkoló. Az alapértelmezett szabálykészlet megfelel a uBlock Origin alapértelmezett szűrőkészletének: @@ -7,15 +7,15 @@ Az alapértelmezett szabálykészlet megfelel a uBlock Origin alapértelmezett s - EasyPrivacy - Peter Lowe hirdetési és nyomkövető-kiszolgálókat tartalmazó listája -További szabályokat adhat hozzá a beállítások oldalon – kattintson a _Fogaskerekek_ ikonra a felugró panelen. +További szabályokat engedélyezhet a beállítások oldalon – kattintson a _Fogaskerekek_ ikonra a felugró panelen. -Az 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 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. -Az 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 az 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. +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 webhelyekhez, hogy jobban szűrhessen ezeken a webhelyeken kozmetikai szűréssel és szkriptlet-injekciókkal. +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 az előugró panelt, és válasszon magasabb szűrési módot, például Optimális vagy Teljes. +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. @@ -23,8 +23,8 @@ Ha elfogadja az uBOL további engedélyekre vonatkozó kérését az aktuális w 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 folyamatban van, a következő célokkal: +Ne feledje, hogy ez még egy folyamatban lévő fejlesztés, a következő célokkal: -- Nincsenek széles körű gazdagép-engedélyek a telepítés során – a kiterjesztett engedélyeket a felhasználó kifejezetten webhelyenként adja meg. +- 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. +- Teljesen deklaratív a nagyobb megbízhatóság, illetve CPU- és memóriahatékonyság érdekében. diff --git a/platform/mv3/description/webstore.hy.txt b/platform/mv3/description/webstore.hy.txt index c847ac69df042..cf9ca080ecd5c 100644 --- a/platform/mv3/description/webstore.hy.txt +++ b/platform/mv3/description/webstore.hy.txt @@ -7,7 +7,7 @@ uBO Lite (uBOL)-ը բովանդակության արգելափակիչ է, որ - EasyPrivacy - Peter Lowe-ի գովազդային և հետագծող սպասարկիչների ցուցակ -Դուք կարող եք ավելացնել ուրիշ կանոններ՝ այցելելով ընտրանքների էջը. կտտացրեք Ժանանվակի_պատկերակին դուրս լողացող վահանակում։ +You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. uBOL-ն ամբողջությամբ դեկլարատիվ է, այսինքն՝ զտման համար անընդհատ կատարվող uBOL գործընթացի կարիք չկա, իսկ CSS/JS արմատավորման վրա հիմնված բովանդակության զտումը հուսալիորեն իրականացվում է զննիչի կողմից, այլ ոչ թե ընդլայնման միջոցով։ Սա նշանակում է, որ uBOL հավելումը չի սպառում մշակիչի/հիշողության որևէ ռեսուրս, երբ տեղի է ունենում գովազդի արգելափակումը. uBOL աշխատանքային գործընթացն աշխատում է _միայն_ երբ Դուք փոփոխություններ եք կատարում դուրս լողացող վահանակում կամ ընտրանքների էջում։ diff --git a/platform/mv3/description/webstore.id.txt b/platform/mv3/description/webstore.id.txt index 33c86b66979cc..92e0b9852bd34 100644 --- a/platform/mv3/description/webstore.id.txt +++ b/platform/mv3/description/webstore.id.txt @@ -7,7 +7,7 @@ Kumpulan aturan bawaan sesuai dengan kumpulan penyaringan bawaan uBlock Origin: - EasyPrivacy - Daftar server iklan dan pelacak Peter Lowe -kamu dapat menambahkan rulesets di halaman opsi -- klik ikon _Cogs_ di panel popup. +Anda dapat mengaktifkan lebih banyak kumpulan pengaturan dengan mengunjungi halaman opsi - klik ikon _Cogs_ pada 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. diff --git a/platform/mv3/description/webstore.it.txt b/platform/mv3/description/webstore.it.txt index 0aa86f4f846a6..edf67f69a8798 100644 --- a/platform/mv3/description/webstore.it.txt +++ b/platform/mv3/description/webstore.it.txt @@ -1,30 +1,30 @@ uBO Lite (uBOL) è un sistema per bloccare contenuti che *non richiede autorizzazioni* basato su MV3. -L'insieme di regole predefinite corrisponde a quello di uBlock Origin: +L'insieme di regole predefinito corrisponde all'insieme di filtri predefinito di uBlock Origin: -- Elenco dei filtri integrati in uBlock Origin +- Liste dei filtri integrati di uBlock Origin - EasyList - EasyPrivacy -- Elenco dei server di tracciatura e pubblicità di Peter Lowe +- Elenco dei server pubblicitari e di tracciamento di Peter Lowe -Puoi aggiungere altre regole nella pagina delle opzioni. Clicca sull'icona _Ingranaggi_ nel pannello a comparsa. +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 un processo uBOL permanente per eseguire il filtraggio e il filtraggio dei contenuti CSS/JS inietattai viene eseguito in modo affidabile dal browser stesso piuttosto che dall'estensione. Ciò significa che lo stesso uBOL non consuma risorse di CPU/memoria mentre il blocco dei contenuti è in corso: il processo di lavoro di servizio di uBOL è richiesto _solo_ quando interagisci con il pannello popup o le pagine delle opzioni. +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ù restrittiva come Ottimale o Completa. +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 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. +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 ulteriori autorizzazioni sul sito corrente, sarà in grado di filtrare meglio i contenuti per il sito corrente. +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 host ampia al momento dell'installazione: le autorizzazioni estese vengono concesse esplicitamente dall'utente in base al sito. +- 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 --git a/platform/mv3/description/webstore.ja.txt b/platform/mv3/description/webstore.ja.txt index 5ae015f74dd89..7a3068b6be7f7 100644 --- a/platform/mv3/description/webstore.ja.txt +++ b/platform/mv3/description/webstore.ja.txt @@ -1,25 +1,25 @@ uBO Lite (uBOL) は権限を必要としない MV3 ベースのコンテンツブロッカーです。 -デフォルトのルールセットは以下の通り。uBlock Origin のデフォルトフィルターセットと同じです。 +デフォルトのルールセットは以下の通りです。uBlock Origin のデフォルトフィルターセットと同じです。 -- uBlock Origin の内製フィルターリスト +- uBlock Origin の内蔵フィルターリスト - EasyList - EasyPrivacy - Peter Lowe’s Ad and tracking server list -オプションページでルールセットを追加できます -- ポップアップ パネルの「歯車」アイコンをクリックします。 +オプションページでルールセットを有効化できます。ポップアップパネルの「歯車」アイコンをクリックしてください。 uBOL は完全に宣言的です。つまり、フィルタリングを行うための恒久的な uBOL プロセスは必要なく、CSS/JS インジェクション ベースのコンテンツフィルタリングは拡張機能ではなくブラウザによって、確実に実行されます。 これは uBOL がコンテンツブロッキングの際に CPU、メモリを消費しないことを意味します。uBOL のサービス ワーカーは ポップアップ パネルや設定ページでのみ必要とされます。 -uBOL はインストール時に広範な「データの読み取りと変更」の権限を要求しません。したがって uBlock Origin やその他の、インストール時に広範な「データの読み取りと変更」の権限を要求するコンテンツ ブロッカーに比べて、行えることが制限されています。 +uBOL はインストール時に広範な「データの読み取りと変更」の権限を要求しません。したがって uBlock Origin やその他の、インストール時に広範な「データの読み取りと変更」の権限を要求するコンテンツブロッカーに比べて、行えることが制限されています。 しかし、ユーザーの選んだ特定のサイトに対する拡張権限を「明示的に」付与すれば、そのサイト上で整形フィルターやスクリプトレットの挿入を用いた優れたフィルタリングを行うことができます。 特定のサイトで拡張された権限を付与するには、ポップアップ パネルを開いて、「最適」や「完全」のようなより高いフィルタリングモードを選択します。 -ブラウザは、現在のサイトで拡張機能によってリクエストされた追加の権限を付与することによってもたらされる影響について警告します。承認または拒否することができます。 +ブラウザーは、現在のサイトで拡張機能によってリクエストされた追加の権限を付与することによってもたらされる影響について警告します。承認または拒否することができます。 -閲覧中のサイトに対するuBOLの追加的な権限要求リクエストを承認すると、そのサイトへのコンテンツフィルタリングの品質をあげることができます。 +現在のサイトでの uBOL のリクエストを承認すると、現在のサイトにより良いフィルターを適用できるようになります。 uBOL の設定ページで既定のフィルタリングモードを設定できます。 「最適」または「完全」を規定のフィルタリング モードに設定した場合、すべてのWebサイトで「データの読み取りと変更」権限を付与する必要があります。 diff --git a/platform/mv3/description/webstore.ka.txt b/platform/mv3/description/webstore.ka.txt index ffcc9851bd291..e659ad87953ee 100644 --- a/platform/mv3/description/webstore.ka.txt +++ b/platform/mv3/description/webstore.ka.txt @@ -7,7 +7,7 @@ uBO Lite (uBOL) *ნებართვებისგან თავისუ - EasyPrivacy - Peter Lowe – სარეკლამო სერვერების სია -შეგიძლიათ სხვა კრებულებიც დაამატეთ პარამეტრების გვერდიდან -- დაწკაპეთ _Cogs_ ხატულაზე ამომხტომ არეში. +შეგიძლიათ სხვა კრებულებიც აამოქმედოთ პარამეტრების გვერდიდან -- დაწკაპეთ _Cogs_ ხატულაზე ამომხტომ არეში. uBOL სრულად დეკლარაციულია, ანუ არაა საჭირო მუდმივად იყოს გაშვებული uBOL-პროცესი გასაფილტრად, CSS/JS ჩანაცვლებით შიგთავსის გაფილტვრას თავად ბრაუზერი უზრუნველყოფს ნაცვლად გაფართოებისა, რაც მეტად საიმედოა. შესაბამისად, uBOL თავად არ დატვირთავს პროცესორს/ოპერატიულს შიგთავსის შეზღუდვის დროს -- uBOL-ის შუამავალი მომსახურე პროცესი საჭიროა _მხოლოდ_ მაშინ, როცა ამომხტომ არესთან ურთიერთქმედებთ ან ცვლით პარამეტრებს. diff --git a/platform/mv3/description/webstore.kk.txt b/platform/mv3/description/webstore.kk.txt index e03fa801ee7f0..7669a5939f98c 100644 --- a/platform/mv3/description/webstore.kk.txt +++ b/platform/mv3/description/webstore.kk.txt @@ -7,7 +7,7 @@ The default ruleset corresponds to uBlock Origin's default filterset: - EasyPrivacy - 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. +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. diff --git a/platform/mv3/description/webstore.kn.txt b/platform/mv3/description/webstore.kn.txt index e03fa801ee7f0..3a7ef1f211ced 100644 --- a/platform/mv3/description/webstore.kn.txt +++ b/platform/mv3/description/webstore.kn.txt @@ -7,11 +7,11 @@ The default ruleset corresponds to uBlock Origin's default filterset: - EasyPrivacy - 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. +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 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 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. +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. @@ -21,9 +21,9 @@ The browser will then warn you about the effects of granting the additional perm 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. +You can set the default filtering mode from uBOL's options page. ನೀವು ಆಪ್ಟಿಮಲ್ ಅಥವಾ ಕಂಪ್ಲೀಟ್ ಮೋಡ್ ಅನ್ನು ಡಿಫಾಲ್ಟ್ ಆಗಿ ಆರಿಸಿದರೆ, ಎಲ್ಲಾ ವೆಬ್‌ಸೈಟ್‌ಗಳಲ್ಲಿನ ಡೇಟಾವನ್ನು ಓದಲು ಮತ್ತು ಮಾರ್ಪಡಿಸಲು ನೀವು uBOL ಗೆ ಅನುಮತಿಯನ್ನು ನೀಡಬೇಕಾಗುತ್ತದೆ. -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. diff --git a/platform/mv3/description/webstore.ko.txt b/platform/mv3/description/webstore.ko.txt index c23291c36032e..2d064281a7cc0 100644 --- a/platform/mv3/description/webstore.ko.txt +++ b/platform/mv3/description/webstore.ko.txt @@ -7,7 +7,7 @@ uBO Lite(uBOL)는 *적은 권한을 요구하는* MV3 기반 콘텐츠 차단기 - EasyPrivacy - Peter Lowe’s Ad and tracking server list -설정 페이지에서 규칙 목록을 더욱 추가할 수 있습니다. 팝업 창의 _Cogs_ 아이콘을 누르세요. +설정 페이지에서 규칙 목록을 더 활성화할 수 있습니다. 팝업 창의 _Cogs_ 아이콘을 누르세요. uBOL은 완전히 선언적이라 필터링 중 영구적으로 실행되는 uBOL 프로세스를 필요로 하지 않으며, CSS/JS 주입 기반 콘텐츠 필터링이 확장 프로그램이 아닌 브라우저 자체에서 더욱 안정적으로 동작합니다. 즉 uBOL 자체는 콘텐츠 차단을 하는 동안 CPU/메모리 리소스를 소비하지 않습니다. uBOL 서비스워커 프로세스는 사용자가 팝업 창이나 설정을 열었을 _때에만_ 동작합니다. diff --git a/platform/mv3/description/webstore.lt.txt b/platform/mv3/description/webstore.lt.txt index e03fa801ee7f0..7669a5939f98c 100644 --- a/platform/mv3/description/webstore.lt.txt +++ b/platform/mv3/description/webstore.lt.txt @@ -7,7 +7,7 @@ The default ruleset corresponds to uBlock Origin's default filterset: - EasyPrivacy - 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. +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. diff --git a/platform/mv3/description/webstore.lv.txt b/platform/mv3/description/webstore.lv.txt index 078cf7f4f9b48..b2b17768b8fad 100644 --- a/platform/mv3/description/webstore.lv.txt +++ b/platform/mv3/description/webstore.lv.txt @@ -7,7 +7,7 @@ Noklusējuma nosacījumu kopa atbilst uBokc Origin noklusējuma aizturēšanas k - EasyPrivacy - Pētera Lova (Peter Lowe) reklāmu un izsakošanas serveru saraksts -Vairāk nosacījumu kopu var pievienot iestatījumu sadaļā -- jāklikšķina _Zobratu_ ikona uznirstošajā logā. +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. diff --git a/platform/mv3/description/webstore.mk.txt b/platform/mv3/description/webstore.mk.txt index e03fa801ee7f0..10a6944e5f205 100644 --- a/platform/mv3/description/webstore.mk.txt +++ b/platform/mv3/description/webstore.mk.txt @@ -1,30 +1,30 @@ -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 add 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 е целосно декларативен, што значи дека не е потребен траен процес на uBOL за филтрирање да се одвива, а филтрирањето на содржини врз основа на инјекција на CSS/JS се извршува со сигурност од самото браузер, а не од самата екстензија. Ова значи дека самиот uBOL не консумира ресурси на CPU/меморија додека блокирањето на содржини е во тек - процесот на службениот работник на uBOL е потребен _само_ кога ќе е потребен со попап панел или страниците со опции. -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. +uBOL не бара широка дозвола за „читање и модификување на податоци“ во време на инсталација, па затоа неговите ограничени можности излезат од кутијата во споредба со uBlock Origin или други блокатори на содржини кои бараат широка „читање и модификување на податоци“ дозволи во време на инсталација. -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. +Сепак, uBOL ви овозможува *експлицитно* да доделите проширени дозволи на специфични страници по ваш избор, така што може подобро да филтрира на тие страници користејќи козметичко филтрирање и инјекции на скрипти. -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. +Ако ја прифатите побараното од 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. +Можете да го поставите подразбираниот режим на филтрирање од страницата со опции на uBOL. Ако ја изберете Оптималната или Комплетната верзија како подразбирана, ќе треба да му овозможите на uBOL дозвола да чита и модифицира податоци на сите веб-страници. -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. +- Целосно декларативен за сигурност и ефикасност на CPU/меморија. diff --git a/platform/mv3/description/webstore.ml.txt b/platform/mv3/description/webstore.ml.txt index 9237bc276067f..547aa6234890f 100644 --- a/platform/mv3/description/webstore.ml.txt +++ b/platform/mv3/description/webstore.ml.txt @@ -7,7 +7,7 @@ uBO Lite (uBOL) ഒരു *അനുമതി-കുറവ്* MV3 അടിസ - ഈസി സ്വകാര്യത - പീറ്റർ ലോവിന്റെ പരസ്യവും ട്രാക്കിംഗ് സെർവർ ലിസ്റ്റും -ഓപ്ഷനുകൾ പേജ് സന്ദർശിച്ച് നിങ്ങൾക്ക് കൂടുതൽ നിയമങ്ങൾ ചേർക്കാൻ കഴിയും -- പോപ്പ്അപ്പ് പാനലിലെ _Cogs_ ഐക്കണിൽ ക്ലിക്കുചെയ്യുക. +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-ന്റെ സേവന വർക്കർ പ്രോസസ്സ് ആവശ്യമാണ്. diff --git a/platform/mv3/description/webstore.mr.txt b/platform/mv3/description/webstore.mr.txt index e03fa801ee7f0..7669a5939f98c 100644 --- a/platform/mv3/description/webstore.mr.txt +++ b/platform/mv3/description/webstore.mr.txt @@ -7,7 +7,7 @@ The default ruleset corresponds to uBlock Origin's default filterset: - EasyPrivacy - 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. +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. diff --git a/platform/mv3/description/webstore.ms.txt b/platform/mv3/description/webstore.ms.txt index 2a48cf613a824..07948a0608641 100644 --- a/platform/mv3/description/webstore.ms.txt +++ b/platform/mv3/description/webstore.ms.txt @@ -7,7 +7,7 @@ Set peraturan lalai sepadan dengan set penapis lalai uBlock Origin: - EasyPrivacy - Senarai pelayan iklan dan penjejakan 'Peter Lowe' -Anda boleh menambah lebih banyak set peraturan dengan melawat halaman pilihan -- klik the _Cogs_ icon pada panel timbul. +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. diff --git a/platform/mv3/description/webstore.nb.txt b/platform/mv3/description/webstore.nb.txt index c45f9a527c080..756166aba704d 100644 --- a/platform/mv3/description/webstore.nb.txt +++ b/platform/mv3/description/webstore.nb.txt @@ -7,7 +7,7 @@ Standardregelsettet tilsvarer standardfiltersettet til uBlock Origin: - EasyPrivacy - Peter Lowe’s Ad and tracking server list -Du kan legge til flere regelsett ved å gå til innstillingssiden -- klikk _Tannhjul_-ikonet i oppsprettspanelet. +You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. 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. diff --git a/platform/mv3/description/webstore.nl.txt b/platform/mv3/description/webstore.nl.txt index ecdf0c3465e51..f94d6521586a9 100644 --- a/platform/mv3/description/webstore.nl.txt +++ b/platform/mv3/description/webstore.nl.txt @@ -7,7 +7,7 @@ De standaard regelset komt overeen met de standaard filterset van uBlock Origin: - EasyPrivacy - Peter Lowe’s Ad and tracking server list -U kunt meer regelsets toevoegen door de optiespagina te bezoeken -- klik op het _tandwielpictogram_ in het pop-uppaneel. +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. diff --git a/platform/mv3/description/webstore.oc.txt b/platform/mv3/description/webstore.oc.txt index e03fa801ee7f0..7669a5939f98c 100644 --- a/platform/mv3/description/webstore.oc.txt +++ b/platform/mv3/description/webstore.oc.txt @@ -7,7 +7,7 @@ The default ruleset corresponds to uBlock Origin's default filterset: - EasyPrivacy - 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. +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. diff --git a/platform/mv3/description/webstore.pa.txt b/platform/mv3/description/webstore.pa.txt index b413fe39a4862..bcd747436bbfe 100644 --- a/platform/mv3/description/webstore.pa.txt +++ b/platform/mv3/description/webstore.pa.txt @@ -7,7 +7,7 @@ uBO Lite (uBOL) ਇੱਕ *ਬਿਨਾਂ ਇਜਾਜ਼ਤਾਂ* ਵਾਲਾ M -ਸੌਖੀ ਪਰਦੇਦਾਰੀ - Peter Lowe ਦੀ ਇਸ਼ਤਿਹਾਰ ਅਤੇ ਟਰੈਕਿੰਗ ਸਰਵਰ ਸੂਚੀ -You can add more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. +ਤੁਸੀਂ ਚੋਣਾਂ ਸਫ਼ੇ ਨੂੰ ਖੋਲ੍ਹ ਕੇ ਹੋਰ ਰੂਲ-ਸੈੱਟ ਸਮਰੱਥ ਕਰ ਕਦੇ ਹੋ -- ਪੌਪ-ਅੱਪ ਪੈਨਲ ਵਿੱਚ _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. @@ -19,7 +19,7 @@ To grant extended permissions on a given site, open the popup panel and pick a h 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. +ਜੇ ਤੁਸੀਂ ਮੌਜੂਦਾ ਸਾਈਟਾਂ ਉੱਤੇ ਹੋਰ ਇਜਾਜਤਾਂ ਲਈ 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. diff --git a/platform/mv3/description/webstore.pl.txt b/platform/mv3/description/webstore.pl.txt index 4f5c5247c872f..a6a17bc2efc8c 100644 --- a/platform/mv3/description/webstore.pl.txt +++ b/platform/mv3/description/webstore.pl.txt @@ -7,7 +7,7 @@ Domyślny zestaw reguł odpowiada domyślnemu zestawowi filtrów uBlock Origin: – EasyPrivacy – lista serwerów śledzących i reklam Petera Lowe'a -Możesz dodać więcej zestawów reguł, odwiedzając stronę opcji – kliknij ikonę _koła zębatego_ w wyskakującym panelu. +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. diff --git a/platform/mv3/description/webstore.pt_BR.txt b/platform/mv3/description/webstore.pt_BR.txt index 884ec649a4499..1478cb2af743e 100644 --- a/platform/mv3/description/webstore.pt_BR.txt +++ b/platform/mv3/description/webstore.pt_BR.txt @@ -7,7 +7,7 @@ O conjunto de regras padrão corresponde ao conjunto de filtros padrão do uBloc - EasyPrivacy - Lista de servidores de anúncios e rastreadores do Peter Lowe -Você pode adicionar mais conjuntos de regras visitando a página das opções -- clique no ícone _Engrenagens_ no painel do pop-up. +Você pode ativar mais conjuntos de regras visitando a página das opções — clique no ícone da _Engranagem_ no painel do popup. 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. diff --git a/platform/mv3/description/webstore.pt_PT.txt b/platform/mv3/description/webstore.pt_PT.txt index fcd3823801406..56560c1d7515d 100644 --- a/platform/mv3/description/webstore.pt_PT.txt +++ b/platform/mv3/description/webstore.pt_PT.txt @@ -7,7 +7,7 @@ O conjunto de regras padrão corresponde ao conjunto de filtros padrão do uBloc - EasyPrivacy - Peter Lowe’s Ad and tracking server list -Pode adicionar 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_ na janela flutuante. 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. diff --git a/platform/mv3/description/webstore.ro.txt b/platform/mv3/description/webstore.ro.txt index 6e1f05d38f5f0..61c81d41a5d24 100644 --- a/platform/mv3/description/webstore.ro.txt +++ b/platform/mv3/description/webstore.ro.txt @@ -7,7 +7,7 @@ Listele de filtre încorporate de uBlock Origin - EasyPrivacy - Oglas Peter Lowe i lista servera za praćenje -Puteți adăuga mai multe seturi de reguli vizitând pagina de opțiuni -- făcând clic pe pictograma _Cogs_ din panoul pop-up +You can enable more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. 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. diff --git a/platform/mv3/description/webstore.ru.txt b/platform/mv3/description/webstore.ru.txt index 637d7cb444841..4abdcf400e533 100644 --- a/platform/mv3/description/webstore.ru.txt +++ b/platform/mv3/description/webstore.ru.txt @@ -7,7 +7,7 @@ uBO Lite (uBOL) — это блокировщик содержимого, *не - EasyPrivacy - Список рекламных и отслеживающих серверов от Peter Lowe -Вы можете добавить больше правил, посетив страницу настроек -- нажмите на значок_Шестеренок на всплывающей панели. +Вы можете активировать больше списков правил на странице настроек -- нажмите на значок _Шестерёнки_ на всплывающей панели. uBOL - полностью декларативный, т.е. для фильтрации не нужен постоянно выполняющийся uBOL процесс, а фильтрация контента, основанная на внедрении CSS/JS, производится непосредственно браузером. Это значит, что дополнение uBOL не расходует ресурсы ЦПУ/памяти, когда происходит блокировка рекламы -- служебный процесс uBOL запускается, _только_ когда вы вносите изменения на всплывающей панели или странице настроек. diff --git a/platform/mv3/description/webstore.si.txt b/platform/mv3/description/webstore.si.txt index e03fa801ee7f0..7669a5939f98c 100644 --- a/platform/mv3/description/webstore.si.txt +++ b/platform/mv3/description/webstore.si.txt @@ -7,7 +7,7 @@ The default ruleset corresponds to uBlock Origin's default filterset: - EasyPrivacy - 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. +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. diff --git a/platform/mv3/description/webstore.sk.txt b/platform/mv3/description/webstore.sk.txt index 686e41f918185..1b2ef413a7b7f 100644 --- a/platform/mv3/description/webstore.sk.txt +++ b/platform/mv3/description/webstore.sk.txt @@ -7,7 +7,7 @@ Predvolený súbor pravidiel zodpovedá predvolenému súboru filtrov uBlock Ori - EasyPrivacy - Zoznam reklamných a sledovacích serverov Petra Lowea -Ďalšie súbory pravidiel môžete pridať na stránke s možnosťami – kliknite na ikonu _súkolesia_ vo vyskakovacom paneli. +Ď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í. diff --git a/platform/mv3/description/webstore.sl.txt b/platform/mv3/description/webstore.sl.txt index e03fa801ee7f0..7669a5939f98c 100644 --- a/platform/mv3/description/webstore.sl.txt +++ b/platform/mv3/description/webstore.sl.txt @@ -7,7 +7,7 @@ The default ruleset corresponds to uBlock Origin's default filterset: - EasyPrivacy - 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. +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. diff --git a/platform/mv3/description/webstore.so.txt b/platform/mv3/description/webstore.so.txt index e03fa801ee7f0..7669a5939f98c 100644 --- a/platform/mv3/description/webstore.so.txt +++ b/platform/mv3/description/webstore.so.txt @@ -7,7 +7,7 @@ The default ruleset corresponds to uBlock Origin's default filterset: - EasyPrivacy - 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. +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. diff --git a/platform/mv3/description/webstore.sq.txt b/platform/mv3/description/webstore.sq.txt index 6b087c3c404ac..197520dde7b87 100644 --- a/platform/mv3/description/webstore.sq.txt +++ b/platform/mv3/description/webstore.sq.txt @@ -7,7 +7,7 @@ Rregullat e tij janë të barasvlershme me filtrat standardë që përdor uBlock - EasyPrivacy - Lista e Peter Lowe për reklamat dhe gjurmuesit -Në faqen e opsioneve mund të shtoni rregulla të tjera – klikoni ikonën e _ingranazhit_ në panelin modal. +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. diff --git a/platform/mv3/description/webstore.sr.txt b/platform/mv3/description/webstore.sr.txt index 065d6c0249db2..da4d7dd90cfa1 100644 --- a/platform/mv3/description/webstore.sr.txt +++ b/platform/mv3/description/webstore.sr.txt @@ -7,7 +7,7 @@ uBO Lite (uBOL) је блокатор садржаја *без дозвола*, - EasyPrivacy - Peter Lowe’s Ad and tracking server list -Можете додати још скупова правила тако што ћете посетити страницу са опцијама - кликните на иконицу зупчаника у искачућем панелу. +Можете омогућити још скупова правила тако што ћете посетити страницу са опцијама -- кликните на иконицу зупчаника у искачућем панелу. uBOL је потпуно декларативан, што значи да нема потребе за трајним uBOL процесом да би дошло до филтрирања, а филтрирање садржаја засновано на убацивању CSS/JS се обавља поуздано од стране самог прегледача, а не проширења. То значи да сам uBOL не троши CPU/меморијске ресурсе док је блокирање садржаја у току -- сервисни радни процес uBOL-а је потребан _само_ када ступите у интеракцију са искачућим панелом или страницама опција. diff --git a/platform/mv3/description/webstore.sv.txt b/platform/mv3/description/webstore.sv.txt index 0355bd0ae45b3..50266fdc13d30 100644 --- a/platform/mv3/description/webstore.sv.txt +++ b/platform/mv3/description/webstore.sv.txt @@ -7,7 +7,7 @@ Standardregeluppsättningen motsvarar uBlock Origins standardfilteruppsättning: - EasyPrivacy - Peter Lowes reklam- och spårningsserverlista -Du kan lägga till fler regeluppsättningar genom att besöka alternativsidan -- klicka på ikonen _Kugghjulet_ i popup-panelen. +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. diff --git a/platform/mv3/description/webstore.sw.txt b/platform/mv3/description/webstore.sw.txt index e03fa801ee7f0..7669a5939f98c 100644 --- a/platform/mv3/description/webstore.sw.txt +++ b/platform/mv3/description/webstore.sw.txt @@ -7,7 +7,7 @@ The default ruleset corresponds to uBlock Origin's default filterset: - EasyPrivacy - 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. +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. diff --git a/platform/mv3/description/webstore.ta.txt b/platform/mv3/description/webstore.ta.txt index e03fa801ee7f0..7669a5939f98c 100644 --- a/platform/mv3/description/webstore.ta.txt +++ b/platform/mv3/description/webstore.ta.txt @@ -7,7 +7,7 @@ The default ruleset corresponds to uBlock Origin's default filterset: - EasyPrivacy - 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. +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. diff --git a/platform/mv3/description/webstore.te.txt b/platform/mv3/description/webstore.te.txt index 2f0c87d02703a..f14c2563da3c5 100644 --- a/platform/mv3/description/webstore.te.txt +++ b/platform/mv3/description/webstore.te.txt @@ -7,7 +7,7 @@ The default ruleset corresponds to uBlock Origin's default filterset: - EasyPrivacy - 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. +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. diff --git a/platform/mv3/description/webstore.th.txt b/platform/mv3/description/webstore.th.txt index e03fa801ee7f0..7669a5939f98c 100644 --- a/platform/mv3/description/webstore.th.txt +++ b/platform/mv3/description/webstore.th.txt @@ -7,7 +7,7 @@ The default ruleset corresponds to uBlock Origin's default filterset: - EasyPrivacy - 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. +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. diff --git a/platform/mv3/description/webstore.tr.txt b/platform/mv3/description/webstore.tr.txt index 125ca901419c5..05bc267cfd5b7 100644 --- a/platform/mv3/description/webstore.tr.txt +++ b/platform/mv3/description/webstore.tr.txt @@ -7,7 +7,7 @@ Varsayılan kural seti, uBlock Origin'in varsayılan filtre setine karşılık g - EasyPrivacy - Peter Lowe'un Reklam ve izleme sunucusu listesi -Seçenekler sayfasını ziyaret ederek daha fazla kural seti ekleyebilirsiniz -- açılan paneldeki _Cogs_ simgesine tıklayın. +Seçenekler ekranına uğrayarak daha çok kuralı uygulatabilirsiniz, 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. diff --git a/platform/mv3/description/webstore.txt b/platform/mv3/description/webstore.txt index e03fa801ee7f0..7669a5939f98c 100644 --- a/platform/mv3/description/webstore.txt +++ b/platform/mv3/description/webstore.txt @@ -7,7 +7,7 @@ The default ruleset corresponds to uBlock Origin's default filterset: - EasyPrivacy - 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. +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. diff --git a/platform/mv3/description/webstore.uk.txt b/platform/mv3/description/webstore.uk.txt index 799bdec1c77aa..e6f8a978d37e8 100644 --- a/platform/mv3/description/webstore.uk.txt +++ b/platform/mv3/description/webstore.uk.txt @@ -1,13 +1,13 @@ -uBO Lite (uBOL) - це блокувальник вмісту на основі MV3, що не потребує дозволу. +uBO Lite (uBOL) - це блокувальник вмісту на основі MV3, що не потребує дозволів. -Усталений набір правил відповідає типовому набору фільтрів uBlock Origin: +Набір правил за замовчанням відповідає типовому набору фільтрів uBlock Origin: - Вбудовані списки фільтрів uBlock Origin - EasyList - EasyPrivacy - Список серверів реклами та стеження від Peter Lowe -Ви можете додати більше наборів правил, перейшовши на сторінку налаштувань — натисніть на піктограму _Шестерень_ на спливній панелі. +Ви можете ввімкнути більше наборів правил, перейшовши на сторінку налаштувань — натисніть на піктограму "Перейти до панелі керування" на спливній панелі. uBOL повністю декларативний, тобто немає необхідності в постійному процесі uBOL для здійснення фільтрації, а фільтрація вмісту на основі CSS/JS-ін'єкцій надійно виконується самим браузером, а не розширенням. Це означає, що сам uBOL не споживає ресурси процесора/пам'яті під час блокування вмісту — службовий робочий процес uBOL потрібен _лише_ під час взаємодії зі спливною панеллю або сторінками опцій. diff --git a/platform/mv3/description/webstore.ur.txt b/platform/mv3/description/webstore.ur.txt index e03fa801ee7f0..5aa5b35b240c1 100644 --- a/platform/mv3/description/webstore.ur.txt +++ b/platform/mv3/description/webstore.ur.txt @@ -1,13 +1,13 @@ -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 -You can add more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. +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. diff --git a/platform/mv3/description/webstore.vi.txt b/platform/mv3/description/webstore.vi.txt index 70d6d591f7ef3..1ea12d09442c1 100644 --- a/platform/mv3/description/webstore.vi.txt +++ b/platform/mv3/description/webstore.vi.txt @@ -7,7 +7,7 @@ Bộ quy tắc mặc định tương tự bộ lọc của uBlock Origin: - EasyPrivacy - Danh sách máy chủ chạy quảng cáo và trình theo dõi của Pete Lowe -Bạn có thể tự thêm quy tắc mới ở trang cài đặt -- click vào icon _Bánh răng_ ở trong cửa sổ popup. +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. diff --git a/platform/mv3/description/webstore.zh_CN.txt b/platform/mv3/description/webstore.zh_CN.txt index b307f534d48bf..e0ae72dd5eb33 100644 --- a/platform/mv3/description/webstore.zh_CN.txt +++ b/platform/mv3/description/webstore.zh_CN.txt @@ -7,7 +7,7 @@ uBO Lite (uBOL) 是一个基于最新浏览器扩展接口(Manifest Version 3 - EasyPrivacy - Peter Lowe’s Ad and tracking server list -您可以通过设置页面添加更多过滤规则列表——点击弹出面板的“齿轮”图标。 +访问选项页面,点击弹出面板中的齿轮图标,即可启用更多规则集。 uBOL 的过滤规则是完全声明式的,并不需要固定保留一个 uBOL 扩展进程,基于 CSS/JS 注入的内容过滤更是交由浏览器进行调度,比起扩展本身更为可靠。 这也即是说当内容被过滤时 uBOL 自身并不占用额外 CPU 和内存资源,只有在您打开弹出面板或是设置页面时才会生成 uBOL 扩展进程。 diff --git a/platform/mv3/description/webstore.zh_TW.txt b/platform/mv3/description/webstore.zh_TW.txt index 1add144ac7cf5..ddc587c6f9762 100644 --- a/platform/mv3/description/webstore.zh_TW.txt +++ b/platform/mv3/description/webstore.zh_TW.txt @@ -1,27 +1,27 @@ uBO Lite (uBOL) 是款以 MV3 為基礎的「免權限」內容阻擋器。 -預設規則集對應了 uBlock Origin 的預設過濾集: +預設規則集對應着 uBlock Origin 的預設過濾集: - uBlock Origin 內建的過濾器清單 - EasyList - EasyPrivacy - Peter Lowe’s Ad and tracking server list -您可以前往選項頁面(按下彈出面板的 **齒輪** 按鈕)新增更多規則集。 +您可以前往選項頁面(按下彈出面板的 **齒輪** 按鈕)啟用更多規則集。 -uBOL 是完全宣告式的,意即過濾過程中不需要持續性的 uBOL 處理程序參與,且以 CSS/JS 注入為基礎進行的內容過濾由可靠的瀏覽器執行,而非是擴充功能。 這就代表 uBOL 在內容阻擋過程不會佔用 CPU 和記憶體資源——除了和彈出面板或選項頁面互動的場景外,都不需要 uBOL 的 Service Worker 程序。 +uBOL 是完全宣告式的,意即過濾過程中不需要持續性的 uBOL 處理程序參與,且以 CSS/JS 注入為基礎的內容過濾由可靠的瀏覽器執行,而非是擴充功能。 這就代表 uBOL 在內容阻擋過程不會佔用 CPU 和記憶體資源——除了和彈出面板或選項頁面互動的場景外,都不需要 uBOL 的 Service Worker 程序。 -uBOL 在安裝期間不需要氾濫的「讀取與修改資料」權限,因此它出廠時的功能和 uBlock Origin 或其他在安裝期間要求「讀取與修改資料」權限的內容阻擋程式相比,會相對受限。 +uBOL 在安裝期間不需要廣泛的「讀取與修改資料」權限,因此它出廠時的功能和 uBlock Origin 或其他在安裝期間要求該權限的內容阻擋程式相比,相對受限。 -不過 uBOL 能讓你 **明確地** 在自選的特定網站授予額外的權限,使其在這些網站的過濾效果可以在元素過濾及 scripetlet 注入的加持下得到提升。 +不過 uBOL 能讓你 **明確地** 在自選的特定網站授予額外的權限,使其在這些網站的過濾效果可以在元素過濾及 scripetlet 注入的加持下提升。 -若要授予指定網站延伸權限,請開啟對話框並選擇更高的過濾模式,如「最佳化」或「完整」。 +若要授予指定網站延伸權限,請開啟彈出面板並選擇更佳的過濾模式,如「最佳」或「完整」。 -瀏覽器接著會警告您授予擴充功能請求的額外權限會帶來的後果,而你需要告訴瀏覽器要同意還是拒絕請求。 +瀏覽器接著會警告您授予擴充功能請求的額外權限所帶來的後果,而你需要告訴瀏覽器要同意還是拒絕。 如果你接受 uBOL 在目前網站請求的額外權限,其在這個網站的過濾效果將會更好。 -您可以在 uBOL 的選項頁面設定預設的過濾模式。 如果您選擇「最佳化」或「完整」為預設的模式,您需要授予 uBOL 讀取與修改所有網站資料的權限。 +您可以在 uBOL 的選項頁面設定預設的過濾模式。 如果您選擇「最佳」或「完整」為預設模式,您需要授予 uBOL 讀取與修改所有網站資料的權限。 注意這尚未完工,最終目標有: diff --git a/platform/mv3/extension/_locales/ar/messages.json b/platform/mv3/extension/_locales/ar/messages.json index 6b6b476ca35f0..c4fd37b0e2c92 100644 --- a/platform/mv3/extension/_locales/ar/messages.json +++ b/platform/mv3/extension/_locales/ar/messages.json @@ -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": { @@ -20,7 +20,7 @@ "description": "appears as tab name in dashboard" }, "aboutPageName": { - "message": "عن التطبيق", + "message": "حول البرنامج", "description": "appears as tab name in dashboard" }, "aboutPrivacyPolicy": { @@ -31,6 +31,10 @@ "message": "وضع التصفية", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "الإبلاغ عن مشكلة في هذا الموقع", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "افتح لوحة التحكم", "description": "English: Click to open the dashboard" @@ -48,7 +52,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAds": { - "message": "اعلانات", + "message": "إعلانات", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupPrivacy": { @@ -99,6 +103,70 @@ "message": "التبعيات الخارجية (متوافقة مع GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "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.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS6P1S1": { + "message": "لتجنب تحميل المتطوعين بتقارير مكررة، يرجى التأكد من أن المشكلة لم يتم الإبلاغ عنها بالفعل.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "العثور على تقارير مماثلة", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "عنوان صفحة الويب", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "صفحة الويب...", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "— اختر إدخالًا —", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "يظهر الإعلانات أو بقايا الإعلانات", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "يحتوي على تراكبات أو إزعاجات أخرى.", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "يكتشف uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "لديه مشاكل متعلقة بالخصوصية", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "تعطل عند تفعيل uBO Lite.", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "يفتح علامات تبويب أو نوافذ غير مرغوب فيها.", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "يؤدي إلى البرامج الضارة والإحتيال", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "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" @@ -147,6 +215,10 @@ "message": "قائمة بأسماء المضيفين التي لن تتم أي تصفية لها", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[أسماء النطاقات الرئيسية فقط]\nexample.com\ngames.example", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "السلوك", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "إظهار عدد الطلبات المحظورة على أيقونة شريط الأدوات", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "تمكين الحظر الصارم", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "سيتم حظر التنقل إلى المواقع غير المرغوب فيها، وسيتم تقديم خيار لك للمتابعة.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "البحث عن القوائم", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "الصفحة محجوبة", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "لقد منع uBO Lite تحميل الصفحة التالية:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "تم حظر الصفحة بسبب وجود فلتر مطابق في {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "الصفحة المحظورة تريد إعادة التوجيه إلى موقع آخر. إذا اخترت المتابعة، فسوف تنتقل مباشرة إلى: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "رجوع", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "إغلاق هذه النافذة", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "لا تحذرني مرة أخرى من هذا الموقع", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "متابعة", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/az/messages.json b/platform/mv3/extension/_locales/az/messages.json index deef8d2510f1b..b0b311a8bb5af 100644 --- a/platform/mv3/extension/_locales/az/messages.json +++ b/platform/mv3/extension/_locales/az/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "İcazəyə ehtiyac duymayan məzmun əngəlləyicisi. Reklamları, izləyiciləri, maynerləri və daha çoxunu quraşdırmadan dərhal sonra əngəlləyir.", + "message": "İcazəyə ehtiyac duymayan məzmun əngəlləyicisi. Reklamları, izləyiciləri, və daha çoxunu quraşdırmadan dərhal sonra əngəlləyir.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -31,6 +31,10 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "İdarəetmə panelini aç", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Create new report", + "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" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "List of websites for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Behavior", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/be/messages.json b/platform/mv3/extension/_locales/be/messages.json index e230e07e93238..0063666a5c310 100644 --- a/platform/mv3/extension/_locales/be/messages.json +++ b/platform/mv3/extension/_locales/be/messages.json @@ -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": { @@ -31,6 +31,10 @@ "message": "рэжым фільтравання", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Паведаміць пра праблему на гэтым вэб-сайце", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Адкрыць панэль кіравання", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Вонкавыя залежнасці (GPLv3-сумяшчальныя):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Паведаміць пра праблему з фільтрам", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "Паведамляйце пра праблемы з фільтрамі, датычныя канкрэтных вэб-сайтаў, праз трэкер праблемuBlockOrigin/uAssets . Патрэбны ўліковы запіс GitHub.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS6P1S1": { + "message": "Каб не абцяжарваць добраахвотнікаў дубляванымі справаздачамі, калі ласка, пераканайцеся, што пра гэтую праблему не паведамлялі раней.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Знайсці падобныя справаздачы", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Адрас вэб-старонкі:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Вэб-старонка…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Выберыце тэму --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Паказвае рэкламу або яе астачу", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Мае накладкі або іншыя недарэчнасці", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Выяўляе uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Мае праблемы, датычныя прыватнасці", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Няспраўнасці пры ўключаным uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Адкрывае непажаданыя карткі або вокны", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Вядзе да шкодных праграм, фішынгу", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "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" @@ -147,6 +215,10 @@ "message": "Спіс назваў хостаў, для якіх не будзе праводзіцца фільтраванне", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[толькі назвы хостаў]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Паводзіны", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Паказваць колькасць заблакаваных запытаў на значку панэлі інструментаў", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Уключыць строгае блакаванне", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Пераход да патэнцыйна непажаданых сайтаў будзе заблакаваны, і вам будзе прапанавана магчымасць працягнуць.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Знайсці спісы", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Старонка заблакаваная", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite папярэдзіў чытанне наступнай старонкі:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Старонка была заблакаваная, бо трапіла ў фільтр праз {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "Заблакаваная старонка мае намер перанакіраваць на іншы сайт. Калі вырашыце працягнуць, вы пяройдзеце непасрэдна на: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "без параметраў", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Вярнуцца", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Закрыць гэтае акно", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Не папярэджваць больш пра гэты сайт", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Працягнуць", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/bg/messages.json b/platform/mv3/extension/_locales/bg/messages.json index f4606dd26de7d..cf834661f3eb5 100644 --- a/platform/mv3/extension/_locales/bg/messages.json +++ b/platform/mv3/extension/_locales/bg/messages.json @@ -31,6 +31,10 @@ "message": "режим на филтриране", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Докладване на проблем с този уебсайт", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Табло с настройки", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Външни зависимости (съвместими с GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Докладване на проблем с филтъра", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "Докладвайте за проблеми с филтрирането на конкретни уебсайтове в uBlockOrigin/uAssets за проследяване на проблеми. Изисква се акаунт в GitHub.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS6P1S1": { + "message": "За да се избегне натоварването на доброволците с дублиращи се доклади, моля, проверете дали проблемът вече не е докладван.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Намиране на подобни доклади", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Адрес на уеб страницата:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Уеб страницата...", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Изберете --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Показва реклами или остатъци от реклами", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Има наслагвания или други неудобства", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Засича uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Има проблеми, свързани с поверителността", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Неправилно функциониране, когато uBO Lite е активиран", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Отваря нежелани раздели или прозорци", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Води до зловреден софтуер, фишинг", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "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" @@ -144,9 +212,13 @@ "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...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Поведение", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Показване на брояч в иконката за блокираните заявки", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Активиране на строгото блокиране", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Навигацията към потенциално нежелани сайтове ще бъде блокирана и ще ви бъде предложена възможността да продължите.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Намиране на списъци", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Страницата е блокирана", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite попречи на зареждането на следната страница:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Страницата е блокирана поради съвпадащ филтър в {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "Блокираната страница иска да ви пренасочи към друг сайт. Ако изберете да продължите, ще преминете директно към: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "без параметри", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Назад", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Затворяне на прозореца", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Не ме предупреждавайте отново за този сайт", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Продължаване", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/bn/messages.json b/platform/mv3/extension/_locales/bn/messages.json index d706ab1c8592c..9087a0ae719d8 100644 --- a/platform/mv3/extension/_locales/bn/messages.json +++ b/platform/mv3/extension/_locales/bn/messages.json @@ -31,6 +31,10 @@ "message": "ফিল্টারিং মোড", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "ড্যাশবোর্ড খুলুন", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "বাহ্যিক নির্ভরতা (GPLv3-সামঞ্জস্যপূর্ণ):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Create new report", + "description": "Text for button which open an external webpage in Support pane" + }, "firstRunSectionLabel": { "message": "স্বাগতম", "description": "The header text for the welcome message section" @@ -147,6 +215,10 @@ "message": "হোস্টনেমের তালিকা যেগুলোর কোনো ফিল্টারিং হবে না", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "আচরণ", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "কতগুলো অনুরোধ ব্লক করা হয়েছে তা টুলবার আইকনে দেখাও", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/br_FR/messages.json b/platform/mv3/extension/_locales/br_FR/messages.json index 30395963560de..1b3d92a2c42d5 100644 --- a/platform/mv3/extension/_locales/br_FR/messages.json +++ b/platform/mv3/extension/_locales/br_FR/messages.json @@ -31,6 +31,10 @@ "message": "mod silañ", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Danevelliñ ur gudenn war al lec'hienn-mañ", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Digeriñ an daolenn-vourzh", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "Dalc'hioù diavaez (a glot gant GPLv3)", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Danevelliñ ur gudenn gant ur sil", + "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" + }, + "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.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Klask danevelloù koulz ha homañ", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Chomlec'h ar bajenn web:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Ar bajenn web-mañ…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Dibab ur seurt --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Diskouez a ra bruderezh pe restachoù bruderezh", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Gwiskadoù pe saotradurioù all en deus", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Diguzhat a ra uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Kudennoù a-fed prevezded he deus", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Ne ya ket mat en-dro p'eo enaouet uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Digeriñ a ra ivinelloù pe prenestroù noazus", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Merkañ ar bejenn web evel \"NSFW\" (“Not Safe For Work”, dizereat evit al labour)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -147,6 +215,10 @@ "message": "Roll anvioù domanioù ha ne vint ket silet.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[anvioù herberc'hierien hepken]\nskouer.com\nchoariou.skouer\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Emzalc'h", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Diskouez an niver a rekedoù bet stanket war arouez ar varrenn-ostilhoù", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enaouiñ ar stankañ strizh", + "description": "Label for a checkbox in the options page" + }, + "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": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Kavout rolloù", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Pajenn stanket", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite en deus miret ar bajenn-mañ da gargañ:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Stanket eo bet ar bajenn abalamour d'ur sil dereat e-barzh {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "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" + }, + "strictblockNoParamsPrompt": { + "message": "kuit a arventennoù", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Distreiñ", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Serriñ ar prenestr-mañ", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Arabat kemenn din diwar-benn al lec'hienn-mañ en-dro", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Kenderc'hel", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/bs/messages.json b/platform/mv3/extension/_locales/bs/messages.json index ab768f6b72003..20c51af871ca1 100644 --- a/platform/mv3/extension/_locales/bs/messages.json +++ b/platform/mv3/extension/_locales/bs/messages.json @@ -31,6 +31,10 @@ "message": "način filtriranja", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Otvorite nadzornu ploču", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Vanjske ovisnosti (kompatibilno s GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Create new report", + "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" @@ -147,6 +215,10 @@ "message": "Lista imena hostova za koja 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...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Ponašanje", "description": "The header text for the 'Behavior' section" @@ -156,7 +228,55 @@ "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { - "message": "Show the number of blocked requests on the toolbar icon", + "message": "Prikažite broj blokiranih zahtjeva na ikoni trake sa alatkama", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/ca/messages.json b/platform/mv3/extension/_locales/ca/messages.json index 5e1f1eb9c7d60..a11095949897a 100644 --- a/platform/mv3/extension/_locales/ca/messages.json +++ b/platform/mv3/extension/_locales/ca/messages.json @@ -31,6 +31,10 @@ "message": "mode de filtre", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Informa d'un problema en aquest lloc web", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Obre el tauler", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Dependències externes (compatibles amb GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Informeu d'un problema de filtre", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "supportS6P1S1": { + "message": "Per evitar carregar els voluntaris amb informes duplicats, verifiqueu que el problema encara no s'hagi notificat.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Cerca d'informes semblants", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Adreça de la pàgina web:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "La pàgina web...", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Trieu una entrada --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Mostra anuncis o restes d'anuncis", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Té superposicions o altres errors", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detecta l'ús de l'uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Té problemes relacionats amb la privadesa", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "No es mostra correctament amb l'uBO Lite habilitat", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Obre pestanyes o finestres no desitjades", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Condueix a programari maliciós, pesca electrònica", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Etiqueta l'enllaç com a «NSFW» (“No apte per al treball”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -147,6 +215,10 @@ "message": "Llistat de noms d'amfitrió als quals no s'aplicarà cap filtre", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[només noms d'amfitrió]\nexemple.com\njocs.exemple\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Comportament", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Mostra el nombre de sol·licituds blocades a la icona de la barra d'eines", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Habilita el blocatge estricte", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Es blocarà la navegació en webs potencialment no desitjables, oferint-vos la possibilitat de continuar.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Cerca llistes", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Pàgina blocada", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "L'uBO Lite ha evitat la càrrega d'aquesta pàgina:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "La pàgina s'ha blocat a causa d'un filtre coincident a {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "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" + }, + "strictblockNoParamsPrompt": { + "message": "sense paràmetres", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Enrere", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Tanca aquesta finestra", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "No em tornis a avisar sobre aquest lloc", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Continua", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/cs/messages.json b/platform/mv3/extension/_locales/cs/messages.json index db051f05d1ad1..3de9ca455861c 100644 --- a/platform/mv3/extension/_locales/cs/messages.json +++ b/platform/mv3/extension/_locales/cs/messages.json @@ -31,6 +31,10 @@ "message": "Filtrovací režim", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Nahlásit problém na této webové stránce", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Otevřít ovládací panel", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Externí závislosti (kompatibilní s GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Nahlásit problém s filtrem", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "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" + }, + "supportFindSpecificButton": { + "message": "Vyhledat podobná hlášení", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Adresa webové stránky:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Webová stránka…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Vyberte položku --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Zobrazuje reklamy nebo zbytky reklam", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Je překrytá nebo má jiné nedostatky", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detekuje uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Má problémy související se soukromím", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Je rozbitá, když je povolen uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Otevírá nechtěné karty nebo okna", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Vede k badwaru, phishingu", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Označit webovou stránku jako “NSFW” (“Není bezpečné pro práci”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -147,6 +215,10 @@ "message": "Seznam názvů hostitelů, pro které nebude probíhat žádné filtrování", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[pouze názvy hostitelů]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Chování", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Zobrazit počet blokovaných požadavků u ikony v panelu nástrojů", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Povolit přísné blokování", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Navigace na potenciálně nežádoucí stránky bude zablokována a bude vám nabídnuta možnost pokračovat.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Najít seznamy", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Stránka zablokována", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite zabránil načtení následující stránky:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Stránka byla zablokována z důvodu shodného filtru v {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "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" + }, + "strictblockNoParamsPrompt": { + "message": "bez parametrů", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Zpět", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Zavřít toto okno", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Nevarujte mě znovu o této stránce", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Pokračovat", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/cv/messages.json b/platform/mv3/extension/_locales/cv/messages.json index 4bbb5e389bf08..b5d2ec8498ea7 100644 --- a/platform/mv3/extension/_locales/cv/messages.json +++ b/platform/mv3/extension/_locales/cv/messages.json @@ -31,6 +31,10 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "List of websites for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Behavior", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/cy/messages.json b/platform/mv3/extension/_locales/cy/messages.json index c9d0e36583d83..3e444d525379e 100644 --- a/platform/mv3/extension/_locales/cy/messages.json +++ b/platform/mv3/extension/_locales/cy/messages.json @@ -12,7 +12,7 @@ "description": "Appears aside each filter list in the _3rd-party filters_ pane" }, "dashboardName": { - "message": "uBO Lite — Dashfwrdd", + "message": "uBO Lite — Dangosfwrdd", "description": "English: uBO Lite — Dashboard" }, "settingsPageName": { @@ -31,6 +31,10 @@ "message": "modd hidlo", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Rhoi gwybod am broblem ar y wefan hon", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Agor y dashfwrdd", "description": "English: Click to open the dashboard" @@ -44,7 +48,7 @@ "description": "Label to be used to hide popup panel sections" }, "3pGroupDefault": { - "message": "Default", + "message": "Diofyn", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAds": { @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "Gofynion allanol (cydnaws â GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Adrodd nam ar hidlydd", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Create new report", + "description": "Text for button which open an external webpage in Support pane" + }, "firstRunSectionLabel": { "message": "Croeso", "description": "The header text for the welcome message section" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "List of websites for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Ymddygiad", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/da/messages.json b/platform/mv3/extension/_locales/da/messages.json index ae494fe74a254..a89b9c535d609 100644 --- a/platform/mv3/extension/_locales/da/messages.json +++ b/platform/mv3/extension/_locales/da/messages.json @@ -31,6 +31,10 @@ "message": "filtreringstilstand", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Anmeld et problem på dette websted", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Åbn kontrolpanelet", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Eksterne afhængigheder (GPLv3-kompatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Anmeld et filterproblem", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "supportS6P1S1": { + "message": "For at undgå at belaste frivillige med dubletanmeldelser, så tjek venligst, at problemet ikke allerede er anmeldt.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find lign. anmeldelser", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Websideadressen:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Websiden…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Vælg problemtype --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Viser annoncer eller annoncerester", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Har overlejringer eller andre gener", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detekterer uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Har fortrolighedsrelaterede problemer", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Fejlfungerer, når uBO Lite er aktiveret", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Åbner uønskede faner eller vinduer", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Fører til badware, phishing", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Mærk websiden som “NSFW” (“Not Safe For Work”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Opret ny anmeldelse", + "description": "Text for button which open an external webpage in Support pane" + }, "firstRunSectionLabel": { "message": "Velkommen", "description": "The header text for the welcome message section" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Liste over værtsnavne, for hvilke ingen filtrering vil ske.", + "message": "Liste over websteder, for hvilke ingen filtrering vil ske.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[kun værtsnavne]\neksempel.dk\nspil.eksempel\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Adfærd", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Vis antallet af blokerede forespørgsler på værktøjsbjælkeikonet", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Aktivér striks blokering", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Navigering til potentielt uønskede websteder blokeres, men man tilbydes muligheden for at fortsætte.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lister", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Side blokeret", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite har forhindret flg. side i at blive indlæst:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Siden blev blokeret grundet et matchende filter i {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "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" + }, + "strictblockNoParamsPrompt": { + "message": "uden parametre", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Gå tilbage", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Luk dette vindue", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Advar ikke igen om dette websted", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Fortsæt", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/de/messages.json b/platform/mv3/extension/_locales/de/messages.json index 13829f3e919fb..22b4bb99bb3cb 100644 --- a/platform/mv3/extension/_locales/de/messages.json +++ b/platform/mv3/extension/_locales/de/messages.json @@ -31,6 +31,10 @@ "message": "Filtermodus", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Ein Problem mit dieser Website melden", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Dashboard öffnen", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Domains mit Schadsoftware", + "message": "Schutz vor Schadsoftware, Sicherheit", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "Externe Abhängigkeiten (GPLv3-kompatibel):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Ein Filterproblem melden", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "supportS6P1S1": { + "message": "Um die Freiwilligen nicht mit doppelten Meldungen zu belasten, vergewissern Sie sich bitte, dass das Problem nicht schon einmal gemeldet wurde.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Ähnliche Meldungen finden", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Adresse der Webseite:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Die Webseite …", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Einen Eintrag auswählen --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Zeigt Werbung oder Werbereste", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Hat Überdeckungen oder andere Belästigungen", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Erkennt uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Hat Datenschutzprobleme", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Funktioniert nicht richtig, wenn uBO Lite aktiviert ist", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Öffnet unerwünschte Tabs oder Fenster", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Führt zu Schadsoftware, Phishing", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Webseite als »NSFW« kennzeichnen (»Unpassend für den Arbeitsplatz«)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Neue Meldung 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" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Liste der Hostnamen, für die nicht gefiltert wird.", + "message": "Liste der Websites, für die nicht gefiltert wird.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[nur Hostnamen]\nexample.com\ngames.example\n…", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Verhalten", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Anzahl der blockierten Anfragen auf dem Symbol in der Symbolleiste anzeigen", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Striktes Blockieren aktivieren", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Die Navigation zu potenziell unerwünschten Websites wird verhindert, jedoch wird eine Möglichkeit zum Fortfahren angeboten.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Listen suchen", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Seite blockiert", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite hat das Laden der folgenden Seite verhindert:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Die Seite wurde aufgrund eines übereinstimmenden Filters in {{listname}} blockiert.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "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" + }, + "strictblockNoParamsPrompt": { + "message": "ohne Parameter", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Zurück", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Dieses Fenster schließen", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Nicht erneut vor dieser Seite warnen", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Fortfahren", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/el/messages.json b/platform/mv3/extension/_locales/el/messages.json index 8e3bc5ed1fe52..5c69bd869de45 100644 --- a/platform/mv3/extension/_locales/el/messages.json +++ b/platform/mv3/extension/_locales/el/messages.json @@ -31,6 +31,10 @@ "message": "λειτουργία φιλτραρίσματος", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Αναφορά ενός ζητήματος σε αυτόν τον ιστότοπο", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Ανοίξτε τον πίνακα ελέγχου", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Εξωτερικές εξαρτήσεις (συμβατές με GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Αναφορά ζητήματος φίλτρου", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "Αναφέρετε ζητήματα φίλτρου για συγκεκριμένους ιστοτόπους στο εργαλείο παρακολούθησης ζητημάτων του uBlockOrigin/uAssets. Απαιτείται λογαριασμός GitHub.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS6P1S1": { + "message": "Για να αποφύγετε την επιβάρυνση των εθελοντών με διπλές αναφορές, βεβαιωθείτε ότι το ζήτημα δεν έχει ήδη αναφερθεί.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Βρείτε παρόμοιες αναφορές", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Διεύθυνση ιστοσελίδας:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Η ιστοσελίδα…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Επιλέξτε μια καταχώρηση --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Εμφανίζει διαφημίσεις ή υπολείμματα διαφημίσεων", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Έχει επικαλύψεις ή άλλες ενοχλήσεις", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Ανιχνεύει το uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Έχει ζητήματα σχετικά με το απόρρητο", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Δυσλειτουργεί όταν είναι ενεργό το uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Ανοίγει ανεπιθύμητες καρτέλες ή παράθυρα", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Οδηγεί σε κακόβουλο λογισμικό, ηλεκτρονικό «ψάρεμα»", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "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" @@ -147,6 +215,10 @@ "message": "Λίστα των hostnames για τα οποία δεν θα πραγματοποιηθεί φιλτράρισμα", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[μόνο ονόματα κεντρικών υπολογιστών]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Συμπεριφορά", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Εμφάνιση του αριθμού των αποκλεισμένων αιτημάτων στο εικονίδιο της γραμμής εργαλείων", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Εύρεση λιστών", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Η σελίδα αποκλείστηκε λόγω αντιστοίχισης φίλτρου στη {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "Η αποκλεισμένη σελίδα θέλει να κάνει ανακατεύθυνση σε άλλο ιστότοπο. Αν επιλέξετε να συνεχίσετε, θα μεταβείτε απευθείας στο: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Επιστροφή", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Κλείσιμο του παραθύρου", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Να μην προειδοποιηθώ ξανά για αυτόν τον ιστότοπο", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Συνέχεια", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/en/messages.json b/platform/mv3/extension/_locales/en/messages.json index 878f3cc80b78c..c40e17428ec7c 100644 --- a/platform/mv3/extension/_locales/en/messages.json +++ b/platform/mv3/extension/_locales/en/messages.json @@ -31,6 +31,10 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "List of websites for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Behavior", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/en_GB/messages.json b/platform/mv3/extension/_locales/en_GB/messages.json index 884d7c1960243..ff21a6e83edec 100644 --- a/platform/mv3/extension/_locales/en_GB/messages.json +++ b/platform/mv3/extension/_locales/en_GB/messages.json @@ -31,6 +31,10 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -147,6 +215,10 @@ "message": "List of hostnames for which no filtering will take place", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Behaviour", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/eo/messages.json b/platform/mv3/extension/_locales/eo/messages.json index ba5cfde43e504..90e4a10343dfd 100644 --- a/platform/mv3/extension/_locales/eo/messages.json +++ b/platform/mv3/extension/_locales/eo/messages.json @@ -31,6 +31,10 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Create new report", + "description": "Text for button which open an external webpage in Support pane" + }, "firstRunSectionLabel": { "message": "Bonvenon", "description": "The header text for the welcome message section" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "List of websites for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Behavior", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/es/messages.json b/platform/mv3/extension/_locales/es/messages.json index 53ff70b95a657..e17dfe967f5e4 100644 --- a/platform/mv3/extension/_locales/es/messages.json +++ b/platform/mv3/extension/_locales/es/messages.json @@ -31,6 +31,10 @@ "message": "modo de filtrado", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Reportar un problema en este sitio web", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Abrir panel de control", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Dominios de malware", + "message": "Protección de malware, seguridad", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "Dependencias externas (compatibles con GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Reportar un problema de filtro", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "supportS6P1S1": { + "message": "Para evitar sobrecargar a voluntarios con reportes duplicados, verifica que el problema no haya sido reportado.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Encontrar reportes similares", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Dirección de la página web:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "La página web...", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Elige una entrada --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Muestra anuncios o restos de anuncios", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Tiene superposiciones u otras molestias", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detecta uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Tiene problemas relacionados con la privacidad", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Funciona mal cuando uBO Lite está habilitado", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Abre pestañas o ventanas no deseadas", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Conduce a malware y phishing", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Etiquetar la página web como “NSFW” (“no es seguro/apropiado para el trabajo”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Crear nuevo reporte", + "description": "Text for button which open an external webpage in Support pane" + }, "firstRunSectionLabel": { "message": "Bienvenida", "description": "The header text for the welcome message section" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Lista de nombres de dominio para los cuales no se realizará ningún filtrado.", + "message": "Lista de sitios web para los cuales no se realizará ningún filtrado.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[solo nombres de dominio]\nejemplo.com\njuegos.ejemplo\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Comportamiento", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Mostrar el número de peticiones bloqueadas en el icono de la barra de herramientas", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Habilitar bloqueo estricto", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "La navegación a sitios potencialmente no deseados será bloqueada, y se te ofrecerá la opción de continuar.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Encontrar listas", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Página bloqueada", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite impidió la carga de la página:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "La página ha sido bloqueada como resultado de un filtro coincidente en {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "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" + }, + "strictblockNoParamsPrompt": { + "message": "sin parámetros", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Regresar", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Cerrar esta ventana", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "No me adviertas de nuevo sobre este sitio", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Continuar", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/et/messages.json b/platform/mv3/extension/_locales/et/messages.json index 69f6aa21932e4..a6dc44ddafb36 100644 --- a/platform/mv3/extension/_locales/et/messages.json +++ b/platform/mv3/extension/_locales/et/messages.json @@ -31,6 +31,10 @@ "message": "filtreerimisrežiim", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Teavita veast selle veebilehega", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Ava töölaud", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Välised sõltuvused (ühilduvad GPLv3-ga):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Teavita filtri veast", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "supportS6P1S1": { + "message": "Vabatahtlike koormamise vältimiseks samade teadetega veenduge, et keegi pole selle murega juba varem pöördunud.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Leidke sarnased aruanded", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Veebilehe aadress:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Veebileht...", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Valige --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Näitab reklaame või reklaami kohatäitjaid", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Omab ülekatteid või teisi nuhtlusi", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Tuvastab uBO Lite'i", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Omab privaatsusega seonduvaid probleeme", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Streigib, kui uBO Lite on kasutusel", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Avab soovimatuid kaarte või aknaid", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Põhjustab pahavara, õngitsuskirju", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Märgi veebileht kui „NSFW” („Ohtlik”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Loo 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" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Hostinimede loend, kus filtreerimine keelatakse", + "message": "Veebilehtede loend, kus filtreid ei kasutata.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[ainult hostinimed]\nnäide.com\nmängud.näide\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Käitumine", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Kuva tööriistariba ikoonil blokeeritud elementide arv", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Luba range tõkestamine", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Kahtlastele veebilehtedele suunamist takistatakse ja pakutakse võimalust jätkamiseks.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Otsi nimekirju", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Lehe sirvimine piiratud", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite ennetas järgmise veebilehe laadimist:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Lehe avamine keelati {{listname}} tõttu.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "Keelatud leht üritab suunata teisele lehele. Jätkates nõustute avama {{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "ilma näitajateta", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Tagasi", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Sulge see aken", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Edaspidi luba mul seda sirvida", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Jätka", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/eu/messages.json b/platform/mv3/extension/_locales/eu/messages.json index 353f3b79c3eed..812e5eada31ca 100644 --- a/platform/mv3/extension/_locales/eu/messages.json +++ b/platform/mv3/extension/_locales/eu/messages.json @@ -31,6 +31,10 @@ "message": "Iragazteko modua", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Ireki lan-lekua", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Kanpo menpekotasunak (GPLv3 lizentziarekin bateragarriak):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Create new report", + "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" @@ -147,6 +215,10 @@ "message": "Filtrorik ezarriko ez zaien zerbitzarien izenak", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[zerbitzari izenak bakarrik]\nadibidea.eus\nexample.com\ngames.example", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "portaera or jokaera", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Tresna-barraren ikonoan blokeatutako eskaeren kopurua erakutsi", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/fa/messages.json b/platform/mv3/extension/_locales/fa/messages.json index a18a6ed3a7cb3..743018c21a4cd 100644 --- a/platform/mv3/extension/_locales/fa/messages.json +++ b/platform/mv3/extension/_locales/fa/messages.json @@ -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": { @@ -31,6 +31,10 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "باز کردن داشبورد", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -80,7 +84,7 @@ "description": "English: Source code (GPLv3)" }, "aboutContributors": { - "message": "Contributors", + "message": "شرکت کنندگان", "description": "English: Contributors" }, "aboutSourceCode": { @@ -99,8 +103,72 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Create new report", + "description": "Text for button which open an external webpage in Support pane" + }, "firstRunSectionLabel": { - "message": "Welcome", + "message": "درود", "description": "The header text for the welcome message section" }, "firstRunDescription": { @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "List of websites for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Behavior", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/fi/messages.json b/platform/mv3/extension/_locales/fi/messages.json index 05d42117aa0ed..905e8319fecb7 100644 --- a/platform/mv3/extension/_locales/fi/messages.json +++ b/platform/mv3/extension/_locales/fi/messages.json @@ -31,6 +31,10 @@ "message": "suodatustila", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Ilmoita ongelmasta tällä verkkosivustolla", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Avaa hallintapaneeli", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Ulkopuoliset riippuvuudet (GPLv3-yhteensopiva):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Ilmoita suodatinongelmasta", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "Ilmoita sivustokohtaisista suodatinongelmista uBlockOrigin/uAssets -ongelmaseurantaan. Vaatii GitHub-tilin.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS6P1S1": { + "message": "Välttääksesi vapaaehtoisten kuormittamisen ylimääräisillä ilmoituksilla, tarkista ensin onko ongelmasta jo ilmoitettu.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Etsi samankaltaisia ilmoituksia", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Verkkosivun osoite:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Verkkosivu…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Valitse aihe --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Näyttää mainoksia tai niiden jäänteitä", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Sisältää peiteruutuja tai muita ärsykkeitä", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Tunnistaa uBO Liten", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Sisältää tietosuojaan liittyviä ongelmia", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Ei toimi oikein uBO Liten ollessa käytössä", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Avaa ei-toivottuja välilehtiä tai ikkunoita", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Johtaa badwareen ja tietojenkalasteluun", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Luokittele verkkosivu \"NSFW\"-tyyppiseksi (\"Not Safe For Work\", eli ns. työpaikalle sopimattomaksi)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Luo 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" @@ -147,6 +215,10 @@ "message": "Listaus osotteista, joita ei suodateta.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[vain isäntänimiä]\nesimerkki.fi\npelit.esimerkki\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Toiminta", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Näytä estettyjen pyyntöjen määrä työkalupalkin kuvakkeessa", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Käytä tiukkaa estoa", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Potentiaalisesti ei-toivottujen sivustojen avaaminen estetään mahdollisuudella jatkaa.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Etsi listoja", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Sivu estettiin", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite on estänyt seuraavan sivun latauksen:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Sivu estettiin listalla {{listname}} olevan sännön perusteella.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "Estetty sivu ohjautuu eri sivustolle. Jos jatkat, siirryt suoraan osoitteeseen {{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "ilman parametreja", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Palaa takaisin", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Sulje tämä ikkuna", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Älä varoita minua tästä sivustosta uudelleen", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Jatka", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/fil/messages.json b/platform/mv3/extension/_locales/fil/messages.json index fe5daa48fba7e..9e5b7cece38a8 100644 --- a/platform/mv3/extension/_locales/fil/messages.json +++ b/platform/mv3/extension/_locales/fil/messages.json @@ -31,6 +31,10 @@ "message": "moda nang pagsasala", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Buksan ang dashboard", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Mga panlabas na dependency (angkop sa GPLv3)", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Create new report", + "description": "Text for button which open an external webpage in Support pane" + }, "firstRunSectionLabel": { "message": "Mabuhay", "description": "The header text for the welcome message section" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "List of websites for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Ugali", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/fr/messages.json b/platform/mv3/extension/_locales/fr/messages.json index 0152c8e9139c3..58cf3803e7f88 100644 --- a/platform/mv3/extension/_locales/fr/messages.json +++ b/platform/mv3/extension/_locales/fr/messages.json @@ -31,6 +31,10 @@ "message": "Mode de filtrage", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Rapporter un problème sur ce site Web", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Ouvrir le Tableau de bord", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Dépendances externes (compatibles GPLv3) :", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Rapporter un problème de filtre", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "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é.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Trouver des rapports similaires", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Adresse de la page Web :", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "La page Web…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Choisir un type --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "affiche des publicités ou des résidus de publicité", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "a une surcouche ou d'autres nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "détecte uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "a des problèmes de confidentialité", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "fonctionne mal quand uBO Lite est activé", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "ouvre des onglets ou fenêtres indésirables", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "conduit à/redirige vers des logiciels malveillants, du hameçonnage", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Marquer la page Web comme \"IPLT\" (Inapproprié Pour Le Travail)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Créer un nouveau rapport", + "description": "Text for button which open an external webpage in Support pane" + }, "firstRunSectionLabel": { "message": "Bienvenue", "description": "The header text for the welcome message section" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Liste des noms de domaine qu'uBO Lite ne devra pas filtrer", + "message": "Liste des noms de domaine pour lesquels aucun filtrage n'aura lieu.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[noms de domaine uniquement]\nexemple.com\njeux.exemple\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Comportement", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Afficher le nombre de requêtes bloquées sur l'icône", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Activer le blocage strict", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "La navigation vers des sites potentiellement indésirables sera bloquée, et vous aurez la possibilité de continuer", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Trouver des listes", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page bloquée", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite a empêché le chargement de cette page :", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "La page a été bloquée à cause d'un filtre correspondant dans {{listname}}", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "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" + }, + "strictblockNoParamsPrompt": { + "message": "sans paramètres", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Précédent", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Fermer cette fenêtre", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Ne plus me prévenir pour ce site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Continuer", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/fy/messages.json b/platform/mv3/extension/_locales/fy/messages.json index f583e4b49e1c1..2c09835ec4d26 100644 --- a/platform/mv3/extension/_locales/fy/messages.json +++ b/platform/mv3/extension/_locales/fy/messages.json @@ -31,6 +31,10 @@ "message": "filtermodus", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "In probleem op dizze website melde", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Dashboerd iepenje", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Eksterne ôfhinklikheden (GPLv3-kompatibel):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "In filterprobleem melde", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "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" + }, + "supportFindSpecificButton": { + "message": "Soartgelikense meldingen sykje", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Adres fan de webside:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "De webside…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Meitsje in kar --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Toant advertinsjes of restanten", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Hat oerlapingen of oare ûngemakken", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detektearret uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Hat privacy-relatearre problemen", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Wurket net as uBO Lite ynskeakele is", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Iepenet net-winske ljepblêden of finsters", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Liedt ta badware, phishing", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "De webside labelje as ‘NSFW’ (‘Not Safe For Work’)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -147,6 +215,10 @@ "message": "List fan hostnammen wêrfoar gjin filtering plakfynt.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[allinnich hostnammen]\nexample.com\ngames.example\n…", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Gedrach", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "It tal blokkearre oanfragen op it arkbalkepiktogram toane", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Strange blokkearring ynskeakelje", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Navigaasje nei potinsjeel net-winske websites wurdt blokkearre, en jo krije de opsje om troch te gean.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Listen sykje", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Side blokkearre", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite hat it laden fan de folgjende side opkeard:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "De side is blokkearre fanwegen in oerienkommend filter yn {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "De blokkearre side wol jo omliede nei in oare website. As jo trochgean, navigearje jo streekrjocht nei: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "sûnder parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Tebek", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Dit finster slute", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "My net mear warskôgje oer dizze website", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Tochgean", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/gl/messages.json b/platform/mv3/extension/_locales/gl/messages.json index 760c65c899a85..c6e3cc2daa151 100644 --- a/platform/mv3/extension/_locales/gl/messages.json +++ b/platform/mv3/extension/_locales/gl/messages.json @@ -31,6 +31,10 @@ "message": "modo de filtrado", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Informar dun problema nesta web", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Abrir o panel", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "Dependencias externas (GPLv3-compatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Informar dun problema co filtro", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "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.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Atopar denuncias parecidas", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Enderezo da páxina web:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "A páxina web...", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Escolle unha opción --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Mostra publicidade ou restos dela", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Ten capas sobreimpostas ou elementos molestos", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detecta uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Ten problemas relacionados coa privacidade", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Funciona mal se uBO Lite está activado", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Abre xanelas ou pestanas non solicitadas", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leva a software malicioso, phishing", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Etiqueta a páxina como «NSFW» (Non axeitada no traballo)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -147,6 +215,10 @@ "message": "Lista de nomes de host para os que non se fará filtrado", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[só nomes de servidor]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Comportamento", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Mostrar na icona da barra o número de peticións bloqueadas", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Activar bloqueo estrito", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Vaise bloquear a navegación en webs potencialmente non desexables, e ofrecerase a opción de bloquealas.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Atopa listas", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Páxina bloqueada", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite evitou que a seguinte páxina se cargase:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Bloqueouse a páxina porque concorda cun filtro de {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "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" + }, + "strictblockNoParamsPrompt": { + "message": "sen parámetros", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Volver", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Pechar esta xanela", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Non volver avisarme sobre esta web", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceder", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/gu/messages.json b/platform/mv3/extension/_locales/gu/messages.json index 4bbb5e389bf08..b5d2ec8498ea7 100644 --- a/platform/mv3/extension/_locales/gu/messages.json +++ b/platform/mv3/extension/_locales/gu/messages.json @@ -31,6 +31,10 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "List of websites for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Behavior", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/he/messages.json b/platform/mv3/extension/_locales/he/messages.json index beb73f27377fd..2bbc73d76ef81 100644 --- a/platform/mv3/extension/_locales/he/messages.json +++ b/platform/mv3/extension/_locales/he/messages.json @@ -31,6 +31,10 @@ "message": "מצב מסנן", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "דווח על בעיה באתר זה", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "פתיחת לוח־המחוונים", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "תלויות חיצוניות (תואם GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "דיווח על בעיית מסנן", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "לדיווח על בעיות באתרים ספציפים יש לפתוח דיווח חדש במעקב הדיווחים של uBlockOrigin/uAssets. נדרש חשבון ב GitHub.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS6P1S1": { + "message": "כדי להימנע מהכבדה על מתנדבים בדווחים כפולים, נא לודא שבעיה דומה טרם דווחה.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "מצאו דיווחים דומים", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "כתובת דף האינטרנט:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "דף האינטרנט…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- בחר קטגוריה --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "הצגת פרסומות או שאריות שלהן", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "קיים ריבוד או מטרד אחר", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "מזהה את uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "בעיות הקשורות לפרטיות", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "כשל תפעולי כאשר uBO Lite פעיל", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "נפתחים לשוניות או חלונות לא רצויים", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "מוביל לנוזקה, פישינג", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "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" @@ -147,6 +215,10 @@ "message": "רשימה של שמות אתרים שלא יתבצע עליהם סינון", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[שמות אתרים בלבד]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "התנהגות", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "הצגת מספר הבקשות החסומות על הסמל", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "הפעלת חסימה קפדנית", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "ניווט אפשרי לאתרים לא רצויים יחסם ותהיה אפשרות להחליט להמשיך.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "חיפוש רשימות", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "הדף נחסם", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite מנע טעינה של הדפים הבאים:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "הדף נחסם בגלל התאמה למסנן מהרשימה {{listname}}", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "הדף החסום רוצה להעביר אותך לאתר אחר. בחירה להמשיך תעבור ישירות ל {{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "ללא פרמטרים", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "חזור", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "סגור חלון זה", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "אל תתריע לי שוב על אתר זה", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "המשך", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/hi/messages.json b/platform/mv3/extension/_locales/hi/messages.json index 244acb89cb7b6..66334c281411a 100644 --- a/platform/mv3/extension/_locales/hi/messages.json +++ b/platform/mv3/extension/_locales/hi/messages.json @@ -31,6 +31,10 @@ "message": "फ़िल्टरिंग मोड", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "इस वेबसाइट पर किसी समस्या को रिपोर्ट करें", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "डैशबोर्ड खोलें", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "बाहरी निर्भरता (GPLv3-compatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Create new report", + "description": "Text for button which open an external webpage in Support pane" + }, "firstRunSectionLabel": { "message": "स्वागत", "description": "The header text for the welcome message section" @@ -147,6 +215,10 @@ "message": "होस्टनामों की सूची जिनके लिए कोई फ़िल्टरिंग नहीं होगी", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[केवल होस्ट का नाम]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "व्यवहार", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "टूलबार आइकन पर अवरुद्ध अनुरोधों की संख्या दिखाएं", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "पृष्ठ को {{listname}} में मेल खाते फ़िल्टर के कारण अवरुद्ध किया गया था.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "ब्लॉक किया गया पेज किसी दूसरी साइट पर रीडायरेक्ट करना चाहता है. अगर आप आगे बढ़ना चुनते हैं, तो आप सीधे इस पर नेविगेट करें: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/hr/messages.json b/platform/mv3/extension/_locales/hr/messages.json index 2ae0291a129f3..116371621df8f 100644 --- a/platform/mv3/extension/_locales/hr/messages.json +++ b/platform/mv3/extension/_locales/hr/messages.json @@ -31,6 +31,10 @@ "message": "Način filtriranja", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Prijavite problem na ovoj web stranici", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Otvori nadzornu ploču", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Vanjski korišteni programi (GPLv3-kompatiblini):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Prijavi problem sa filterom", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "supportS6P1S1": { + "message": "Kako biste izbjegli opterećivanje volontera duplim prijavama, provjerite nije li problem već prijavljen.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Nađi slične prijave", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Adresa web stranice:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Web stranica...", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Odaberite unos --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Prikazuje oglase ili ostatke oglasa", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Ima overlaye ili druge smetnje", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Otkriva uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Ima problema u vezi s privatnošću", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Neispravno kada je uBO Lite omogućen", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Otvara neželjene kartice ili prozore", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Vodi do zloćudnog softvera, krađe identiteta", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Označite web stranicu kao “NSFW” (“Nije sigurno za rad”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Napravi novu prijavu", + "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" @@ -147,6 +215,10 @@ "message": "Popis naziva hostova za koje se neće izvršiti filtriranje.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[samo nazivi hostova]\nexample.com\ngames.example", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Ponašanje", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Prikaži broj blokiranih zahtjeva na ikoni alatne trake", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Omogući strogo blokiranje", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Navigacija do potencijalno nepoželjnih stranica bit će blokirana i bit će vam ponuđena opcija za nastavak.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Pronađi liste", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Stranica blokirana", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite je spriječio učitavanje sljedeće stranice:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Stranica je blokirana zbog odgovarajućeg filtra u {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "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" + }, + "strictblockNoParamsPrompt": { + "message": "bez parametara", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Idi natrag", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Zatvori ovaj prozor", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Ne upozoravaj me više za ovu web stranicu", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Nastavi", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/hu/messages.json b/platform/mv3/extension/_locales/hu/messages.json index 3ec2b0e2ece25..9583d57488d17 100644 --- a/platform/mv3/extension/_locales/hu/messages.json +++ b/platform/mv3/extension/_locales/hu/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Kísérleti, engedélyt nem igénylő nélküli tartalomblokkoló. A telepítés után azonnal blokkolja a hirdetéseket, nyomkövetőket, bányászokat és egyebeket.", + "message": "Engedélyt nem igénylő tartalomblokkoló. A telepítés után azonnal blokkolja a hirdetéseket, nyomkövetőket, bányászokat és egyebeket.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -31,6 +31,10 @@ "message": "szűrési mód", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Oldalon lévő probléma jelentése", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Vezérlőpult megnyitása", "description": "English: Click to open the dashboard" @@ -99,16 +103,80 @@ "message": "Külső függőségek (GPLv3-kompatibilis):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Szűrőhiba jelentése", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "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.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Hasonló jelentések keresése", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "A weboldal címe:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "A weboldal…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Válasszon egy bejegyzést --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Hirdetéseket vagy azok maradványait jeleníti meg", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Átfedő vagy egyéb zavaró elemeket tartalmaz", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Észleli az uBO Lite-ot", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Adatvédelmi problémákat vet fel", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Hibásan működik, ha a uBO Lite be van kapcsolva", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Kéretlen lapokat vagy ablakokat nyit meg", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Kártékony programokhoz, adathalászathoz vezet", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "A weboldal megjelölése „NSFW”-ként („Not Safe For Work”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Új jelentés létrehozása", + "description": "Text for button which open an external webpage in Support pane" + }, "firstRunSectionLabel": { - "message": "Üdvözlünk", + "message": "Üdvözöljük", "description": "The header text for the welcome message section" }, "firstRunDescription": { - "message": "Alapértelmezés szerint az Alap 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.", + "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ő", + "message": "Alapértelmezett szűrési mód", "description": "The header text for the default filtering mode section" }, "defaultFilteringModeDescription": { @@ -116,11 +184,11 @@ "description": "This describes the default filtering mode setting" }, "filteringMode0Name": { - "message": "Nincs szűrés", + "message": "nincs szűrés", "description": "Name of blocking mode 0" }, "filteringMode1Name": { - "message": "alapok", + "message": "alapvető", "description": "Name of blocking mode 1" }, "filteringMode2Name": { @@ -128,7 +196,7 @@ "description": "Name of blocking mode 2" }, "filteringMode3Name": { - "message": "elkészült", + "message": "teljes", "description": "Name of blocking mode 3" }, "basicFilteringModeDescription": { @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Azon hosztnevek listája, amelyek esetében nem történik szűrés", + "message": "Azon gépnevek listája, amelyek esetében nem történik szűrés.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[csak kiszolgálónevek]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Viselkedés", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Blokkolt kérések számának megjelenítése az eszköztárikonon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Szigorú blokkolás engedélyezése", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Az esetleges nem kívánatos webhelyekre való navigáció blokkolva lesz, és rákérdez arra, hogy folytatja-e.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Listák keresése", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Oldal blokkolva", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "A uBO Lite megakadályozta a következő oldal betöltését:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Az oldal a(z) {{listname}} listában lévő illeszkedő szűrő miatt blokkolva lett.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "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" + }, + "strictblockNoParamsPrompt": { + "message": "paraméterek nélkül", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Vissza", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Ablak bezárása", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Ne figyelmeztessen többet erről az oldalról", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Folytatás", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/hy/messages.json b/platform/mv3/extension/_locales/hy/messages.json index 6de0ec8a17e86..4d8a874100ec3 100644 --- a/platform/mv3/extension/_locales/hy/messages.json +++ b/platform/mv3/extension/_locales/hy/messages.json @@ -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": { @@ -31,6 +31,10 @@ "message": "զտման ռեժիմ", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Բացել կառավահանը", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Արտաքին կախվածություններ (GPLv3-համատեղելի)՝", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Create new report", + "description": "Text for button which open an external webpage in Support pane" + }, "firstRunSectionLabel": { "message": "Բարի գալուստ", "description": "The header text for the welcome message section" @@ -147,6 +215,10 @@ "message": "Հյուրերի անունների ցանկ, որոնց համար զտում չի իրականացվի", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Վարք", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Ցուցադրել արգելափակված հայտերի քանակը գործիքների վահանակին", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/id/messages.json b/platform/mv3/extension/_locales/id/messages.json index 421f091afb516..4afc32fd7a072 100644 --- a/platform/mv3/extension/_locales/id/messages.json +++ b/platform/mv3/extension/_locales/id/messages.json @@ -31,6 +31,10 @@ "message": "mode filter", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Laporkan masalah pada situs ini", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Buka dasbor", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Dependensi eksternal (kompatibel GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Laporkan masalah filter", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "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" + }, + "supportFindSpecificButton": { + "message": "Temukan laporan serupa", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Alamat laman web:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Laman web…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pilih entri --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Menampilkan iklan atau sejenisnya", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Memiliki overlay atau gangguan lainnya", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Mendeteksi uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Memiliki masalah terkait privasi", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfungsi saat uBO Lite diaktifkan", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Membuka tab atau jendela yang tidak diinginkan", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Mengarah ke perangkat lunak jahat, phishing", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Label laman web sebagai “NSFW” (“Not Safe For Work”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -147,6 +215,10 @@ "message": "Daftar nama host yang tidak akan difilter.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hanya nama host]\ncontoh.com\npermainan.contoh\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Perilaku", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Tampilkan jumlah permintaan yang diblokir pada ikon toolbar", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Aktifkan pemblokiran ketat", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Navigasi ke situs yang mungkin tidak diinginkan akan diblokir, dan Anda akan ditawari opsi untuk melanjutkan.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Temukan daftar", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Halaman diblokir", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite telah mencegah pemuatan halaman berikut:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "tanpa parameter", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Kembali", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Tutup jendela ini", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Jangan peringatkan saya lagi tentang situs ini", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Lanjutkan", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/it/messages.json b/platform/mv3/extension/_locales/it/messages.json index beea941700736..e454824ab0d3b 100644 --- a/platform/mv3/extension/_locales/it/messages.json +++ b/platform/mv3/extension/_locales/it/messages.json @@ -8,7 +8,7 @@ "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { - "message": "{{ruleCount}} Regole, convertite da {{filterCount}} filtri di rete", + "message": "{{ruleCount}} regole, convertite da {{filterCount}} filtri di rete", "description": "Appears aside each filter list in the _3rd-party filters_ pane" }, "dashboardName": { @@ -16,7 +16,7 @@ "description": "English: uBO Lite — Dashboard" }, "settingsPageName": { - "message": "Opzioni", + "message": "Impostazioni", "description": "appears as tab name in dashboard" }, "aboutPageName": { @@ -31,6 +31,10 @@ "message": "Modalità di filtraggio", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Segnala un problema su questo sito web", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Apri il pannello di controllo", "description": "English: Click to open the dashboard" @@ -60,15 +64,15 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { - "message": "Disturbi", + "message": "Elementi fastidiosi", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMisc": { - "message": "Generici", + "message": "Varie", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupRegions": { - "message": "Lingue e regioni", + "message": "Regioni, lingue", "description": "Header for a ruleset section in 'Filter lists pane'" }, "aboutChangelog": { @@ -92,27 +96,91 @@ "description": "Link text to translations repo" }, "aboutFilterLists": { - "message": "Elenco filtri", + "message": "Liste dei filtri", "description": "Link text to uBO's own filter lists repo" }, "aboutDependencies": { - "message": "Dipendenze esterne (in linea con la GPL v3):", + "message": "Dipendenze esterne (GPLv3-compatibili):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Segnala un problema di 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.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS6P1S1": { + "message": "Per evitare di gravare sui volontari con segnalazioni doppie, verifica che il problema non sia già stato segnalato.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Trova segnalazioni simili", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Indirizzo della pagina web:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "La pagina web...", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "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à", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Presenta sovrapposizioni o altri disturbi", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Rileva uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Ha problemi relativi alla privacy", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunzionamenti quando uBO Lite è abilitato", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Apre schede o finestre indesiderate", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Porta a badware, phishing", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Contrassegna la pagina web come “NSFW”. (“Not Safe For Work”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Crea una nuova segnalazione", + "description": "Text for button which open an external webpage in Support pane" + }, "firstRunSectionLabel": { - "message": "Ciao", + "message": "Benvenuto", "description": "The header text for the welcome message section" }, "firstRunDescription": { - "message": "Hai installato uBO Lite. Scegli il filtro predefinito da usare ovunque.\n\nL'impostazione di fabbrica prevede la modalità Basilare che non richiede alcun tipo di autorizzazione. Puoi decidere di attivare il filtro avanzato se vuoi concedere a uBO Lite l'autorizzazione a rielaborare i dati di tutti i siti web che visiti, in modo da avere un sistema di filtraggio con altre funzioni in più.", + "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": "Filtro predefinito", + "message": "Modalità di filtraggio predefinita", "description": "The header text for the default filtering mode section" }, "defaultFilteringModeDescription": { - "message": "Il filtraggio predefinito può essere sostituito dal filtraggio personalizzato. Puoi regolare il filtraggio per ogni singolo sito web al fine di ottenere il risultato migliore. Ognuno dei filtraggi 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 su un determinato sito web in base alla modalità che funziona meglio su quel sito. Ogni modalità presenta vantaggi e svantaggi.", "description": "This describes the default filtering mode setting" }, "filteringMode0Name": { @@ -120,7 +188,7 @@ "description": "Name of blocking mode 0" }, "filteringMode1Name": { - "message": "di base", + "message": "basilare", "description": "Name of blocking mode 1" }, "filteringMode2Name": { @@ -132,31 +200,83 @@ "description": "Name of blocking mode 3" }, "basicFilteringModeDescription": { - "message": "Filtro di rete basilare basato su un elenco selezionato di filtri.\n\nNon servono autorizzazioni per rielaborare i dati dei siti web.", + "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.", "description": "This describes the 'basic' filtering mode" }, "optimalFilteringModeDescription": { - "message": "Filtro di rete avanzato in aggiunta al filtro avanzato basato su un elenco selezionato di filtri.\n\nRichiede delle autorizzazioni specifiche per rielaborare i dati dei 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 su tutti i siti web.", "description": "This describes the 'optimal' filtering mode" }, "completeFilteringModeDescription": { - "message": "Filtro avanzato di rete in aggiunta al filtro esteso basato su un elenco selezionato di filtri.\n\nRichiede autorizzazioni estese per leggere e modificare i dati da ogni sito web.\n\nIl filtro esteso richiede più memoria e un maggiore impegno del processore.", + "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.", "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Elenco degli host per i quali non viene effettuato nessun filtraggio", + "message": "Lista dei nomi host per i quali non verrà effettuato alcun filtraggio.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[solo nomi di host]\nesempio.com\ngiochi.esempio\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Comportamento", "description": "The header text for the 'Behavior' section" }, "autoReloadLabel": { - "message": "Ricarica la pagina quando scegli un altro metodo di filtraggio", + "message": "Ricarica la pagina automaticamente quando cambi la modalità di filtraggio", "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { - "message": "Mostra il numero di richieste bloccate sull'icona nella barra degli strumenti", + "message": "Mostra il numero delle richieste bloccate sull'icona nella barra degli strumenti", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Abilita il blocco rigido", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "La navigazione verso siti potenzialmente indesiderati verrà bloccata e ti verrà offerta la possibilità di procedere.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Trova elenchi", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Pagina bloccata", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite ha impedito alla seguente pagina di caricarsi:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "La pagina è stata bloccata a causa di un filtro corrispondente in {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "La pagina bloccata vuole reindirizzare a un altro sito. Se scegli di procedere, navigherai direttamente su: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "senza parametri", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Torna indietro", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Chiudi questa finestra", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Non avvisarmi di nuovo riguardo questo sito", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Procedi", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/ja/messages.json b/platform/mv3/extension/_locales/ja/messages.json index 28ad8753b9d6f..e94d710cfb7a7 100644 --- a/platform/mv3/extension/_locales/ja/messages.json +++ b/platform/mv3/extension/_locales/ja/messages.json @@ -31,6 +31,10 @@ "message": "フィルタリングモード", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "このサイト上での問題を報告", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "ダッシュボードを開く", "description": "English: Click to open the dashboard" @@ -99,12 +103,76 @@ "message": "外部依存関係 (GPLv3 互換):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "フィルターの問題を報告する", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "uBlockOrigin/uAssets issue tracker で特定のウェブサイトでのフィルターの問題を報告します。GitHub アカウントが必要です", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS6P1S1": { + "message": "重複した報告によってボランティアに負担をかけないように、問題がすでに報告されていないか確認してください。", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "似た報告を探す", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "ウェブページのアドレス:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "ウェブページ…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- エントリーを選択 --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "広告または消し残りが表示される", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "オーバーレイなど邪魔なものがある", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "uBO Lite が検出される", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "プライバシーに関連する問題がある", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "uBO Lite 有効時に機能しなくなる", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "勝手にタブやウィンドウが開く", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "悪質ソフトやフィッシングへの誘導", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "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 を信用してもらえるなら、データの読み書きや変更の権限を許可してもらえればすべてのサイトに対してより詳細なフィルタリングを有効化できます。", + "message": "uBO Lite のインストールが完了しました。すべてのサイトに適用するデフォルトのフィルタリングモードを選んでください。\n\nデフォルトでは、データの読み書きの権限が必要ない基本モードが選択されています。 uBO Lite を信用する場合は、データの読み書きや変更の権限を許可して、すべてのサイトに対してより高度なフィルタリングを有効化できます。", "description": "Descriptive text shown at first install time only " }, "defaultFilteringModeSectionLabel": { @@ -147,6 +215,10 @@ "message": "フィルタリングを行わないホスト名のリスト", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[ホスト名のみ]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "動作", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "ブロックしたリクエストの数をツールバーのアイコンに表示", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "厳格なブロックを有効化", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "望ましくない可能性のあるサイトへのナビゲーションはブロックされ、次に進むためのオプションが表示されます。", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "ブロックしたページ", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite はこのページの読み込みをブロックしています:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "パラメータを除いた URL", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "戻る", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "このウィンドウを閉じる", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "今後このサイトに関する警告を表示しない", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "続行する", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/ka/messages.json b/platform/mv3/extension/_locales/ka/messages.json index c728583fa9ef8..6b1e1608fb41f 100644 --- a/platform/mv3/extension/_locales/ka/messages.json +++ b/platform/mv3/extension/_locales/ka/messages.json @@ -31,6 +31,10 @@ "message": "გაფილტვრის რეჟიმი", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "ამ საიტზე ხარვეზის მოხსენება", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "სამართავის გახსნა", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "ცალკეული დაქვემდებარებული პროექტები (GPLv3-თან თავსებადი):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "ფილტრის ხარვეზის მოხსენება", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "ცალკეულ საიტზე ფილტრების ხარვეზების მოსახსენებლად გამოიყენეთ uBlockOrigin/uAssets ხარვეზების აღსარიცხავი. დაგჭირდებათ GitHub-ანგარიში.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS6P1S1": { + "message": "მოხალისეები რომ არ მოცდნენ ერთნაირი მოსხენებების ნახვით, გთოხვთ გადაამოწმოთ, უკვე ხომ არაა გაგზავნილი საჩივარი ამ ხარვეზზე.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "იპოვეთ მსგავსი მოხსენებები", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "ვებგვერდის მისამართი:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "ვებგვერდი...", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- შეარჩიეთ --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "აჩვენებს რეკლამებს ან მის ნარჩენებს", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "ადებს შემაწუხებელ შრეებსა და მისთანებს", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "ამჩნევს, რომ uBO Lite ჩართულია", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": " პირადულობის დაცვის ხარვეზებითაა", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "შეფერხებით მუშაობს, როცა uBO Lite ჩართულია", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "ხსნის არასასურველ ჩანართებს ან ფანჯრებს", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "გადადის მავნე, თაღლითურ შიგთავსზე", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "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" @@ -147,6 +215,10 @@ "message": "სია მისამართებისა, რომლებზეც ფილტრები არ იმოქმედებს", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[მხოლოდ მისამართის საწყისი]\nexample.com\ngames.example\n…", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "მოქმედება", "description": "The header text for the 'Behavior' section" @@ -156,7 +228,55 @@ "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { - "message": "Show the number of blocked requests on the toolbar icon", + "message": "აჩვენეთ დაბლოკილი მოთხოვნების რაოდენობა ხელსაწყოთა ზოლის ხატულაზე", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "მკაცრი შეზღუდვის ჩართვა", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "შეიზღუდა სავარაუდოდ არასასურველ გვერდებზე გადასვლა, საშუალება გეძლევათ, მაინც განაგრძოთ.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "სიების მოძიება", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "შეზღუდული გვერდი", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite ზღუდავს მოცემული გვერდის ჩატვირთვას:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "გვერდი შეიზღუდა ფილტრით {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "ეს შეზღუდული გვერდი ცდილობს თქვენს სხვა საიტზე გადაყვანას. თუ განაგრძობთ, გაიხსნება: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "პარამეტრების გარეშე", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "უკან დაბრუნება", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "ამ ფანჯრის დახურვა", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "აღარ მეცნობოს ამ საიტზე", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "გაგრძელება", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/kk/messages.json b/platform/mv3/extension/_locales/kk/messages.json index 4bbb5e389bf08..b5d2ec8498ea7 100644 --- a/platform/mv3/extension/_locales/kk/messages.json +++ b/platform/mv3/extension/_locales/kk/messages.json @@ -31,6 +31,10 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "List of websites for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Behavior", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/kn/messages.json b/platform/mv3/extension/_locales/kn/messages.json index 30c578f94ffdd..94a0f5288d013 100644 --- a/platform/mv3/extension/_locales/kn/messages.json +++ b/platform/mv3/extension/_locales/kn/messages.json @@ -28,9 +28,13 @@ "description": "Link to privacy policy on GitHub (English)" }, "popupFilteringModeLabel": { - "message": "filtering mode", + "message": "ಫಿಲ್ಟರಿಂಗ್ ಮೋಡ್", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "ಡ್ಯಾಶ್‌ಬೋರ್ಡ್ ತೆರೆಯಿರಿ", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,12 +103,76 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Create new report", + "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.", + "message": "ನೀವು ಈಗಷ್ಟೇ uBO Lite ಅನ್ನು ಸ್ಥಾಪಿಸಿರುವಿರಿ. ಇಲ್ಲಿ ನೀವು ಎಲ್ಲಾ ವೆಬ್‌ಸೈಟ್‌ಗಳಲ್ಲಿ ಬಳಸಲು ಡಿಫಾಲ್ಟ್ ಫಿಲ್ಟರಿಂಗ್ ಮೋಡ್ ಅನ್ನು ಆಯ್ಕೆ ಮಾಡಬಹುದು.\n\nಪೂರ್ವನಿಯೋಜಿತವಾಗಿ, ಸಾಮಾನ್ಯ ಮೋಡ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ ಏಕೆಂದರೆ ಇದು ಡೇಟಾವನ್ನು ಓದಲು ಮತ್ತು ಮಾರ್ಪಡಿಸಲು ಅನುಮತಿಯ ಅಗತ್ಯವಿಲ್ಲ. ನೀವು uBO Lite ಅನ್ನು ನಂಬುತ್ತಿದ್ದರೆ, ಡೀಫಾಲ್ಟ್ ಆಗಿ ಎಲ್ಲಾ ವೆಬ್‌ಸೈಟ್‌ಗಳಿಗೆ ಹೆಚ್ಚು ಸುಧಾರಿತ ಫಿಲ್ಟರಿಂಗ್ ಸಾಮರ್ಥ್ಯಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ಎಲ್ಲಾ ವೆಬ್‌ಸೈಟ್‌ಗಳಲ್ಲಿನ ಡೇಟಾವನ್ನು ಓದಲು ಮತ್ತು ಮಾರ್ಪಡಿಸಲು ನೀವು ವಿಶಾಲವಾದ ಅನುಮತಿಯನ್ನು ನೀಡಬಹುದು.", "description": "Descriptive text shown at first install time only " }, "defaultFilteringModeSectionLabel": { @@ -124,7 +192,7 @@ "description": "Name of blocking mode 1" }, "filteringMode2Name": { - "message": "optimal", + "message": "ಸೂಕ್ತ", "description": "Name of blocking mode 2" }, "filteringMode3Name": { @@ -144,11 +212,15 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "List of websites for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { - "message": "Behavior", + "message": "ನಡವಳಿಕೆ", "description": "The header text for the 'Behavior' section" }, "autoReloadLabel": { @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/ko/messages.json b/platform/mv3/extension/_locales/ko/messages.json index d066b63af68a8..a8a6767a081ed 100644 --- a/platform/mv3/extension/_locales/ko/messages.json +++ b/platform/mv3/extension/_locales/ko/messages.json @@ -31,6 +31,10 @@ "message": "필터링 모드", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "이 사이트의 이슈를 신고하기", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "대시보드 열기", "description": "English: Click to open the dashboard" @@ -92,13 +96,77 @@ "description": "Link text to translations repo" }, "aboutFilterLists": { - "message": "필터 리스트", + "message": "필터 목록", "description": "Link text to uBO's own filter lists repo" }, "aboutDependencies": { "message": "외부 의존성 (GPLv3 호환):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "필터 이슈 신고", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "특정 웹사이트에서 발생하는 필터 이슈를 uBlockOrigin/uAssets 이슈 트래커에 신고할 수 있습니다. GitHub 계정이 필요합니다.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS6P1S1": { + "message": "봉사자들이 중복 신고로 인해 부담을 겪지 않도록, 해당 이슈가 이미 신고되지는 않았는지 확인해주시기 바랍니다.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "유사한 신고 탐색", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "웹페이지 주소:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "웹페이지가…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- 주제 선택 --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "광고나 광고 흔적을 보여줍니다", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "오버레이나 기타 성가신 요소를 보여줍니다", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "uBO Lite 사용을 감지합니다", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "개인정보 보호 관련 이슈가 있습니다", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "uBO Lite를 켜면 깨집니다", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "원치 않는 탭이나 창을 엽니다", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "악성코드, 피싱으로 유도합니다", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "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" @@ -147,6 +215,10 @@ "message": "필터링을 비활성화할 호스트 이름 목록", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[호스트 이름만 작성]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "동작", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "차단된 요청 개수를 도구 모음 아이콘에 표시", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "엄격한 차단 켜기", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "잠재적으로 좋지 않은 사이트로의 접속을 차단하고, 사용자가 진행할지 선택하도록 합니다.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "목록 찾기", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "페이지 차단됨", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite가 다음 페이지를 불러오지 못하게 했습니다.", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "이 페이지가 {{listname}} 내 필터링 항목에 해당하여 차단되었습니다.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "차단된 페이지에서 다른 사이트로 이동하려 합니다. 계속하시면, {{url}} 주소로 바로 이동합니다.", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "매개변수 없음", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "뒤로", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "창 닫기", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "다시는 이 사이트에 대해 경고하지 않기", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "계속", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/lt/messages.json b/platform/mv3/extension/_locales/lt/messages.json index 3f0bad82bbc7b..964c21d1f5bb8 100644 --- a/platform/mv3/extension/_locales/lt/messages.json +++ b/platform/mv3/extension/_locales/lt/messages.json @@ -31,6 +31,10 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "Išorinės priklausomybės (suderinamos su „GPLv3“):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -144,11 +212,15 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "List of websites for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { - "message": "Behavior", + "message": "Elgsena", "description": "The header text for the 'Behavior' section" }, "autoReloadLabel": { @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/lv/messages.json b/platform/mv3/extension/_locales/lv/messages.json index a37ba6dda83c1..53b675ac7de02 100644 --- a/platform/mv3/extension/_locales/lv/messages.json +++ b/platform/mv3/extension/_locales/lv/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Izmēģinājuma, bezatļauju satura aizturētājs. Aiztur reklāmas, izsekotājus, kriptoracējus un vēl uzreiz pēc uzstādīšanas.", + "message": "Bezatļauju satura aizturētājs. Aiztur reklāmas, izsekotājus, kriptoracējus un daudz ko citu uzreiz pēc uzstādīšanas.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -24,13 +24,17 @@ "description": "appears as tab name in dashboard" }, "aboutPrivacyPolicy": { - "message": "Privātuma nosacījumi", + "message": "Konfidencialitātes nosacījumi", "description": "Link to privacy policy on GitHub (English)" }, "popupFilteringModeLabel": { "message": "aizturēšanas veids", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Ziņot par nepilnību šajā tīmekļa vietnē", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Atvērt vadības paneli", "description": "English: Click to open the dashboard" @@ -60,7 +64,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { - "message": "Traucējumi", + "message": "Kaitinoši elementi", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMisc": { @@ -99,12 +103,76 @@ "message": "Ārējās atkarības (GPLv3 saderīgas):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Ziņot par aizturēšanas filtra nepilnību", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "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.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Meklēt līdzīgus ziņojumus", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Tīmekļa lapas adrese:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Tīmekļa lapa…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Atlasīt ierakstu --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Rāda reklāmas vai to paliekas", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Ir pārklājumi vai citi traucējumi", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Nosaka uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Ir ar privātumu saistītas nepilnības", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Darbības traucējumi, kad ir iespējots uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Atver nevēlamas cilnes vai logus", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Noved pie ļaunatūras, pikšķerēšanas", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Atzīmēt šo lapu kā “nav droša skatīšanai darbā (NSFW)” (“Not Safe For Work”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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 ir 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.", + "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": { @@ -128,7 +196,7 @@ "description": "Name of blocking mode 2" }, "filteringMode3Name": { - "message": "pilnīgais", + "message": "pilnais", "description": "Name of blocking mode 3" }, "basicFilteringModeDescription": { @@ -136,17 +204,21 @@ "description": "This describes the 'basic' filtering mode" }, "optimalFilteringModeDescription": { - "message": "Attīstītāka tīkla aizturēšana ar atsevišķu paplašinātu aizturēšanu, izmantojot atlasītos aizturēšanas sarakstus.\n\nNepieciešamas plašas atļaujas lasīt un mainīt visu tīmekļa vietņu datus.", + "message": "Labāka tīkla aizturēšana ar atsevišķu paplašinātu aizturēšanu, izmantojot atlasītos aizturēšanas sarakstus.\n\nNepieciešamas plašas atļaujas lasīt un mainīt visu tīmekļa vietņu datus.", "description": "This describes the 'optimal' filtering mode" }, "completeFilteringModeDescription": { - "message": "Attīstītāka tīkla aizturēšana ar pamata un papildu paplašinātu aizturēšanu, izmantojot atlasītos aizturēšanas sarakstus.\n\nNepieciešamas plašas atļaujas lasīt un mainīt visu tīmekļa vietņu datus.\n\nPamata paplašinātā aizturēšana var izraisīt paaugstinātu tīmekļa vietnes resursu izmantošanu.", + "message": "Pilna tīkla aizturēšana ar pamata un papildu paplašinātu aizturēšanu, izmantojot atlasītos aizturēšanas sarakstus.\n\nNepieciešamas plašas atļaujas lasīt un mainīt visu tīmekļa vietņu datus.\n\nPamata paplašinātā aizturēšana var izraisīt paaugstinātu tīmekļa vietnes resursu izmantošanu.", "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Saraksts ar saimniekdatoru nosaukumiem, kuriem netiks pielietota aizturēšana", + "message": "Saraksts ar resursdatoru nosaukumiem, kuriem netiks pielietota aizturēšana", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[tikai resursdatoru nosaukumi]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Uzvedība", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Rādīt aizturēto pieprasījumu skaitu rīkjoslas ikonā", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Iespējot stingro aizturēšanu", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Iespējami nevēlamu vietņu apmeklēšana tiks aizturēta, un tiks piedāvāta iespēja turpināt.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Atrast sarakstus", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Lapa aizturēta", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite novērsa šīs lapas ielādēšanu:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Lapa tika aizturēta, jo atbilst aizturētājam sarakstā {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "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" + }, + "strictblockNoParamsPrompt": { + "message": "bez parametriem", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Doties atpakaļ", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Aizvērt šo logu", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Nebrīdināt vairs par šo vietni", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Turpināt", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/mk/messages.json b/platform/mv3/extension/_locales/mk/messages.json index cb7631b2bbf95..39a5b44a517e6 100644 --- a/platform/mv3/extension/_locales/mk/messages.json +++ b/platform/mv3/extension/_locales/mk/messages.json @@ -4,7 +4,7 @@ "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": { @@ -31,8 +31,12 @@ "message": "Начини на прочистување", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Пријави проблем на оваа веб-страница", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { - "message": "Отварање на Контролна Табла", + "message": "Отварање на Контролна плоча", "description": "English: Click to open the dashboard" }, "popupMoreButton": { @@ -40,7 +44,7 @@ "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": { @@ -56,11 +60,11 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "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": { @@ -72,91 +76,207 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "aboutChangelog": { - "message": "Changelog", + "message": "Промени", "description": "" }, "aboutCode": { - "message": "Source code (GPLv3)", + "message": "Изворен код (GPLv3)", "description": "English: Source code (GPLv3)" }, "aboutContributors": { - "message": "Contributors", + "message": "Сов contributors", "description": "English: Contributors" }, "aboutSourceCode": { - "message": "Source code", + "message": "Изворен код", "description": "Link text to source code repo" }, "aboutTranslations": { - "message": "Translations", + "message": "Преводи", "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": "Пријави проблем со филтерот", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "Пријавете проблеми со филтерите за специфични веб-страници до uBlockOrigin/uAssets issue tracker. Потребен е GitHub профил.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS6P1S1": { + "message": "За да се избегне оптоварување на волонтерите со дупликат пријави, ве молиме проверете дали проблемот веќе не е пријавен.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Најди слични пријави", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Адреса на веб-страницата:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Веб-страницата…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Изберете внос --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Покажува реклами или остатоци од реклами", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Има преOverlayи или други непријатности", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Детектира uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Има проблеми поврзани со приватноста", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Има многу проблеми кога е вклучен uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Отвора непожелни табови или прозорци", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Води до злонамерен софтвер, фишинг", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "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": "Welcome", + "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.", + "message": "Токму ја инсталиравте uBO Lite. Овде можете да изберете режим на филтрирање по подразбирање што ќе го користите на сите веб-страници.\n\nПо подразбирање, е избран режимот Основен затоа што не бара дозвола за читање и модификација на податоци. Ако му верувате на uBO Lite, можете да му дадете ширување на дозволата за читање и модификација на податоци на сите веб-страници за да овозможите попрецизни способности за филтрирање на сите веб-страници по подразбирање.", "description": "Descriptive text shown at first install time only " }, "defaultFilteringModeSectionLabel": { - "message": "Default filtering mode", + "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": { - "message": "basic", + "message": "основен", "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 hostnames for which no filtering will take place.", + "message": "Листата на веб-страници за кои нема да се врши филтрирање.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[само домени]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { - "message": "Behavior", + "message": "Понашање", "description": "The header text for the 'Behavior' section" }, "autoReloadLabel": { - "message": "Automatically reload page when changing filtering mode", + "message": "Автоматски освежи ја страницата кога се менува режимот на филтрирање", "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { - "message": "Show the number of blocked requests on the toolbar icon", + "message": "Прикажи го бројот на блокирани барања на иконата во алатникот", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Најди листи", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/ml/messages.json b/platform/mv3/extension/_locales/ml/messages.json index 2bffd1a1ffc61..2dd452d2c989f 100644 --- a/platform/mv3/extension/_locales/ml/messages.json +++ b/platform/mv3/extension/_locales/ml/messages.json @@ -31,6 +31,10 @@ "message": "ഫിൽട്ടറിംഗ് മോഡ്", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "ഡാഷ്ബോർഡ് തുറക്കുക", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "ബാഹ്യ ഡിപൻഡൻസികൾ (ജിപിൽവി3-അനുയോജ്യമായത്):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Create new report", + "description": "Text for button which open an external webpage in Support pane" + }, "firstRunSectionLabel": { "message": "സ്വാഗതം", "description": "The header text for the welcome message section" @@ -147,6 +215,10 @@ "message": "ഫിൽട്ടറിംഗ് നടക്കാത്ത ഹോസ്റ്റ് നെയിമുകളുടെ ലിസ്റ്റ്", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "പെരുമാറ്റം", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/mr/messages.json b/platform/mv3/extension/_locales/mr/messages.json index 4bbb5e389bf08..b5d2ec8498ea7 100644 --- a/platform/mv3/extension/_locales/mr/messages.json +++ b/platform/mv3/extension/_locales/mr/messages.json @@ -31,6 +31,10 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "List of websites for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Behavior", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/ms/messages.json b/platform/mv3/extension/_locales/ms/messages.json index 817a81f39af9d..828adc67eef3d 100644 --- a/platform/mv3/extension/_locales/ms/messages.json +++ b/platform/mv3/extension/_locales/ms/messages.json @@ -31,6 +31,10 @@ "message": "mod penapisan", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Buka papan pemuka", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "Pergantungan luaran (serasi dengan GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Create new report", + "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" @@ -147,6 +215,10 @@ "message": "Senarai nama hos yang tiada penapisan akan berlaku", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Tingkah laku", "description": "The header text for the 'Behavior' section" @@ -156,7 +228,55 @@ "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { - "message": "Show the number of blocked requests on the toolbar icon", + "message": "Tunjukkan bilangan permintaan yang disekat pada ikon bar alat", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/nb/messages.json b/platform/mv3/extension/_locales/nb/messages.json index ed850b77db4ad..c65495bd664c5 100644 --- a/platform/mv3/extension/_locales/nb/messages.json +++ b/platform/mv3/extension/_locales/nb/messages.json @@ -31,6 +31,10 @@ "message": "filtreringsmodus", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Åpne dashbordet", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Eksterne avhengigheter (GPLv3-kompatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Create new report", + "description": "Text for button which open an external webpage in Support pane" + }, "firstRunSectionLabel": { "message": "Velkommen", "description": "The header text for the welcome message section" @@ -147,6 +215,10 @@ "message": "Liste over vertsnavn 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...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Virkemåte", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Vis antall blokkerte forespørsler på verktøylinjeikonet", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/nl/messages.json b/platform/mv3/extension/_locales/nl/messages.json index d73b801d6118f..c567d2d6704ed 100644 --- a/platform/mv3/extension/_locales/nl/messages.json +++ b/platform/mv3/extension/_locales/nl/messages.json @@ -31,6 +31,10 @@ "message": "filtermodus", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Een probleem op deze website melden", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Dashboard openen", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Externe afhankelijkheden (GPLv3-compatibel):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Een filterprobleem melden", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "supportS6P1S1": { + "message": "Controleer of het probleem niet eerder is gemeld om te voorkomen dat vrijwilligers met dubbele meldingen worden belast.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Soortgelijke meldingen zoeken", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Adres van de webpagina:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "De webpagina…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Maak een keuze --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Toont advertenties of restanten", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Heeft overlappingen of andere ongemakken", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detecteert uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Heeft privacy-gerelateerde problemen", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Werkt niet als uBO Lite is ingeschakeld", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opent ongewenste tabbladen of vensters", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leidt tot badware, phishing", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "De webpagina labelen als ‘NSFW’ (‘Not Safe For Work’)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Nieuwe melding 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" @@ -147,6 +215,10 @@ "message": "Lijst van hostnamen waarvoor geen filtering plaatsvindt.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[alleen hostnamen]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Gedrag", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Het aantal geblokkeerde aanvragen op het werkbalkpictogram tonen", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Strenge blokkering inschakelen", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Navigatie naar mogelijk ongewenste websites wordt geblokkeerd, en u krijgt de mogelijkheid om door te gaan.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Lijsten zoeken", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Pagina geblokkeerd", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite heeft het laden van de volgende pagina voorkomen:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "De pagina is geblokkeerd vanwege een overeenkomend filter in {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "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" + }, + "strictblockNoParamsPrompt": { + "message": "zonder parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Teruggaan", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Dit venster sluiten", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Mij niet meer waarschuwen over deze website", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Doorgaan", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/oc/messages.json b/platform/mv3/extension/_locales/oc/messages.json index 4bbb5e389bf08..b5d2ec8498ea7 100644 --- a/platform/mv3/extension/_locales/oc/messages.json +++ b/platform/mv3/extension/_locales/oc/messages.json @@ -31,6 +31,10 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "List of websites for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Behavior", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/pa/messages.json b/platform/mv3/extension/_locales/pa/messages.json index 868cc48068375..fbf91d2ece372 100644 --- a/platform/mv3/extension/_locales/pa/messages.json +++ b/platform/mv3/extension/_locales/pa/messages.json @@ -31,6 +31,10 @@ "message": "ਫਿਲਟਰ ਕਰਨ ਦਾ ਮੋਡ", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "ਇਸ ਵੈੱਬਸਾਈਟ ਉੱਤੇ ਮਸਲੇ ਬਾਰੇ ਰਿਪੋਰਟ ਕਰੋ", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "ਡੈਸ਼ਬੋਰਡ ਨੂੰ ਖੋਲ੍ਹੋ", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "ਬਾਹਰੀ ਨਿਰਭਰਤਾਵਾਂ (GPLv3-ਅਨੁਕੂਲ):", "description": "Shown in the About pane" }, + "supportS6H": { + "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.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "ਰਲਦੀਆਂ ਰਿਪੋਰਟਾਂ ਲੱਭੋ", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "ਵੈੱਬ-ਸਫ਼ੇ ਦਾ ਸਿਰਨਾਵਾਂ:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "ਵੈੱਬ ਸਫ਼ਾ…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "ਇਸ਼ਤਿਹਾਰ ਜਾਂ ਇਸ਼ਤਿਹਾਰ ਦੀ ਰਹਿੰਦ-ਖੂੰਦ ਦਿਖਾਉਂਦਾ ਹੈ", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "ਪਰਦੇਦਾਰੀ ਸੰਬੰਧੀ ਮਸਲੇ ਹਨ", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "ਬੇਲੋੜੀਆਂ ਟੈਬਾਂ ਜਾਂ ਵਿੰਡੋ ਖੋਲ੍ਹਦਾ ਹੈ", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "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" @@ -147,6 +215,10 @@ "message": "ਹੋਸਟ-ਨਾਵਾਂ ਦੀ ਸੂਚੀ, ਜਿਨ੍ਹਾਂ ਲਈ ਕੋਈ ਫਿਲਟਰ ਨਹੀਂ ਕੀਤਾ ਜਾਵੇਗਾ", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "ਰਵੱਈਆ", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/pl/messages.json b/platform/mv3/extension/_locales/pl/messages.json index 1c7b89f236beb..ededd11838d77 100644 --- a/platform/mv3/extension/_locales/pl/messages.json +++ b/platform/mv3/extension/_locales/pl/messages.json @@ -31,6 +31,10 @@ "message": "Tryb filtrowania", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Zgłoś problem z tą stroną", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Otwórz panel sterowania", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Zewnętrzne zależności (kompatybilne z GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Zgłoś problem z filtrem", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "supportS6P1S1": { + "message": "Aby uniknąć obciążania wolontariuszy zduplikowanymi zgłoszeniami, sprawdź, czy problem nie został już zgłoszony.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Znajdź podobne raporty", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Adres strony internetowej:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Strona internetowa…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "— Wybierz pozycję —", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Wyświetla reklamy lub ich pozostałości", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Ma nakładki lub inne niedogodności", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Wykrywa uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Ma problemy związane z prywatnością", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Nieprawidłowe działanie po włączeniu uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Otwiera niepożądane karty lub okna", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Prowadzi do szkodliwego oprogramowania, phishingu", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Oznacz stronę internetową jako „NSFW” („Not Safe For Work”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -147,6 +215,10 @@ "message": "Lista nazw hostów, dla których nie będzie stosowane żadne filtrowanie", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[tylko nazwy hostów]\nexample.com\ngry.przykład\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Zachowanie", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Wyświetlaj liczbę zablokowanych żądań na ikonie paska narzędzi", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Włącz ścisłe blokowanie", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Nawigacja do potencjalnie niepożądanych witryn zostanie zablokowana i pojawi się opcja kontynuowania.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Znajdź listy", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Strona zablokowana", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite nie pozwolił załadować się następującej stronie:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Strona została zablokowana z powodu pasującego filtra na liście {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "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" + }, + "strictblockNoParamsPrompt": { + "message": "bez parametrów", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Wstecz", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Zamknij to okno", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Nie ostrzegaj mnie ponownie o tej witrynie", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Kontynuuj", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/pt_BR/messages.json b/platform/mv3/extension/_locales/pt_BR/messages.json index e6265efab5275..b92f5b59579eb 100644 --- a/platform/mv3/extension/_locales/pt_BR/messages.json +++ b/platform/mv3/extension/_locales/pt_BR/messages.json @@ -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 com menos permissões — Bloqueie anúncios, rastreadores, mineradores e mais imediatamente após a instalação", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -31,6 +31,10 @@ "message": "modo de filtragem", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Reportar um problema neste site da web", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Abrir painel", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Dependências externas (compatíveis com GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Reportar um problema com o filtro", + "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.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS6P1S1": { + "message": "Pra evitar sobrecarregar os voluntários com relatórios duplicados por favor verifique se o problema já não foi reportado.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Achar relatórios similares", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Endereço da página da web:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "A página da web…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "— Escolha uma entrada —", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Mostra os 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", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detecta o uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Tem problemas relacionados a privacidade", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Funciona mal quando o uBO Lite está ativado", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Abre abas ou janelas indesejadas", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leva a badware, phishing", + "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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Criar novo relatório", + "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" @@ -147,6 +215,10 @@ "message": "Lista de nomes dos hospedeiros para os quais nenhuma filtragem acontecerá.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[só nomes de hospedeiros]\nexemplo.com\njogos.exemplo", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Comportamento", "description": "The header text for the 'Behavior' section" @@ -156,7 +228,55 @@ "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { - "message": "Mostrar o número de solicitações bloqueadas no ícone da barra de ferramentas", + "message": "Mostrar o número de requisições bloqueadas no ícone da barra de ferramentas", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Ativar bloqueio rigoroso", "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Achar listas", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Página bloqueada", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "O uBO Lite impediu o carregamento da seguinte página:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "A página foi bloqueada por causa de um filtro que combina no {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "A página bloqueada quer redirecionar para outro site. Se você escolher prosseguir, você navegará diretamente para: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "sem parâmetros", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Voltar", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Fechar esta janela", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Não me avise de novo sobre este site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Prosseguir", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/pt_PT/messages.json b/platform/mv3/extension/_locales/pt_PT/messages.json index 511db27ff621a..d02147916eecf 100644 --- a/platform/mv3/extension/_locales/pt_PT/messages.json +++ b/platform/mv3/extension/_locales/pt_PT/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Um bloqueador de conteúdo sem permissões. Bloqueia anúncios, rastreadores, mineradores de criptomoedas e muito mais, imediatamente após a instalação.", + "message": "Um bloqueador de conteúdo sem permissões. 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": { @@ -31,6 +31,10 @@ "message": "modo de filtragem", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Relatar um problema neste website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Abrir o painel de controlo", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Dependências externas (compatíveis com GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Relatar um problema de filtro", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "supportS6P1S1": { + "message": "Para evitar sobrecarregar os voluntários com relatórios duplicados, verifique se o problema ainda não foi relatado.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Encontrar relatórios semelhantes", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Endereço da página web:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "A página web…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Escolha uma entrada --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "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", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Deteta o uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Tem problemas relacionados com a privacidade", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Falha quando o uBO Lite está ativado", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Abre separadores ou janelas indesejáveis", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leva a badware e phishing", + "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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Criar novo relatório", + "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" @@ -144,19 +212,71 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Lista de nomes de anfitriões para os quais não será efetuada qualquer filtragem.", + "message": "Lista de nomes de websites para os quais não será efetuada qualquer filtragem.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[apenas nomes de anfitriões]\nexemplo.com\njogos.exemplo\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Comportamento", "description": "The header text for the 'Behavior' section" }, "autoReloadLabel": { - "message": "Recarrega automaticamente a página ao mudar o modo de filtragem", + "message": "Recarregar automaticamente a página ao mudar o modo de filtragem", "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { - "message": "Mostra o número de pedidos bloqueados no ícone da barra de ferramentas", + "message": "Mostrar o número de pedidos bloqueados no ícone da barra de ferramentas", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Ativar bloqueio estrito", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "A navegação para sites potencialmente indesejáveis será bloqueada e ser-lhe-á dada a opção de proceder.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Encontrar listas", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Página bloqueada", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "O uBO Lite impediu a seguinte página de ser carregada:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "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": { + "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" + }, + "strictblockNoParamsPrompt": { + "message": "sem parâmetros", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Voltar", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Fechar esta janela", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Não me avisar novamente acerca deste site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceder", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/ro/messages.json b/platform/mv3/extension/_locales/ro/messages.json index 70f9bf60ed171..8c29e9a458135 100644 --- a/platform/mv3/extension/_locales/ro/messages.json +++ b/platform/mv3/extension/_locales/ro/messages.json @@ -8,7 +8,7 @@ "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { - "message": "{{ruleCount}} de reguli convertite din {{filterCount}} filtre de rețea", + "message": "{{ruleCount}} de reguli, convertite din {{filterCount}} filtre de rețea", "description": "Appears aside each filter list in the _3rd-party filters_ pane" }, "dashboardName": { @@ -31,6 +31,10 @@ "message": "Mod de filtrare", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Deschide panoul de control", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Dependențe externe (compatibile GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Create new report", + "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" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Lista numelor mașinilor pentru care nu se va face filtrare", + "message": "Lista numelor site-urilor pentru care nu se va face filtrare", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Comportament", "description": "The header text for the 'Behavior' section" @@ -156,7 +228,55 @@ "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { - "message": "Show the number of blocked requests on the toolbar icon", + "message": "Arată numărul cererilor blocate pe simbolul extensiei", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/ru/messages.json b/platform/mv3/extension/_locales/ru/messages.json index f13511e62cf28..bd89af9f8d8a6 100644 --- a/platform/mv3/extension/_locales/ru/messages.json +++ b/platform/mv3/extension/_locales/ru/messages.json @@ -31,6 +31,10 @@ "message": "режим фильтрации", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Сообщить о проблеме на этом сайте", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Открыть панель управления", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Внешние зависимости (совместимые с GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Сообщить о проблеме в фильтре", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "Сообщайте о проблемах с фильтрами на определённых сайтах в трекер ошибок uBlockOrigin/uAssets. Требуется учётная запись в GitHub.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS6P1S1": { + "message": "Чтобы не обременять волонтеров повторяющимися отчетами, пожалуйста, убедитесь, что о данной проблеме еще не сообщали.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Найти похожие отчеты", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Адрес веб-страницы:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Веб-страница…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Выберите категорию --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Показывается реклама или ее заполнители", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Всплывающие окна или другие помехи", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Обнаруживается uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Проблемы, связанные с приватностью", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Неполадки при работе uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Открываются нежелательные вкладки или окна", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Вредоносное ПО, фишинг", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "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" @@ -147,6 +215,10 @@ "message": "Список имён хостов, для которых не будет производиться фильтрация.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[только имена хостов]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Поведение", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Показывать количество заблокированных запросов на иконке в панели инструментов", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Включить строгую блокировку", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Переход к потенциально нежелательным сайтам будет заблокирован, и будет дана возможность продолжить переход на сайт", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Найти списки", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Страница заблокирована", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite предотвратил загрузку следующей страницы:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Веб-страница была заблокирована из-за попадания в фильтр из {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "Заблокированная страница собирается перенаправить вас на другой сайт. Если вы решите продолжить, вы перейдете непосредственно на: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "без параметров", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Назад", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Закрыть это окно", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Больше не предупреждать меня об этом сайте", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Продолжить", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/si/messages.json b/platform/mv3/extension/_locales/si/messages.json index 4bbb5e389bf08..e411dbb45a2ca 100644 --- a/platform/mv3/extension/_locales/si/messages.json +++ b/platform/mv3/extension/_locales/si/messages.json @@ -4,103 +4,171 @@ "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": "Settings", + "message": "සැකසුම්", "description": "appears as tab name in dashboard" }, "aboutPageName": { - "message": "About", + "message": "පිළිබඳ", "description": "appears as tab name in dashboard" }, "aboutPrivacyPolicy": { - "message": "Privacy policy", + "message": "රහස්‍යතා ප්‍රතිපත්තිය", "description": "Link to privacy policy on GitHub (English)" }, "popupFilteringModeLabel": { - "message": "filtering mode", + "message": "පෙරීමේ ප්‍රකාරය", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "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": { - "message": "Ads", + "message": "දැන්වීම්", "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 domains", + "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'" }, "aboutChangelog": { - "message": "Changelog", + "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": { - "message": "Translations", + "message": "පරිවර්තන", "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": "පෙරහන් ගැටලු වාර්තා කරන්න", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "සමාන වාර්තා සොයන්න", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "අඩවියේ ලිපිනය:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "වියමන පිටුව…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- නිවේශිතයක් තෝරන්න --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "uBO Lite අනාවරණය කරයි", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "අනවශ්‍ය පටිති හෝ කවුළු අරියි", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "නව වාර්තාවක් සාදන්න", + "description": "Text for button which open an external webpage in Support pane" + }, "firstRunSectionLabel": { - "message": "Welcome", + "message": "සාදරයෙන් පිළිගනිමු", "description": "The header text for the welcome message section" }, "firstRunDescription": { @@ -108,7 +176,7 @@ "description": "Descriptive text shown at first install time only " }, "defaultFilteringModeSectionLabel": { - "message": "Default filtering mode", + "message": "පෙරනිමි පෙරීමේ ප්‍රකාරය", "description": "The header text for the default filtering mode section" }, "defaultFilteringModeDescription": { @@ -116,19 +184,19 @@ "description": "This describes the default filtering mode setting" }, "filteringMode0Name": { - "message": "no filtering", + "message": "පෙරීමක් නැත", "description": "Name of blocking mode 0" }, "filteringMode1Name": { - "message": "basic", + "message": "මූලික", "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": { @@ -144,19 +212,71 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "පෙරීමක් නොවන අඩවි ලැයිස්තුව.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[සත්කාරක පමණි]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { - "message": "Behavior", + "message": "හැසිරීම", "description": "The header text for the 'Behavior' section" }, "autoReloadLabel": { - "message": "Automatically reload page when changing filtering mode", + "message": "පෙරීමේ ප්‍රකාරය වෙනස් වූ විට පිටුව ස්වයංක්‍රීයව යළි පූරණය කරන්න", "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { - "message": "Show the number of blocked requests on the toolbar icon", + "message": "මෙවලම් තීරු නිරූපකයේ අවහිර කළ ඉල්ලීම් ගණන පෙන්වන්න", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/sk/messages.json b/platform/mv3/extension/_locales/sk/messages.json index 91ebfc926a1c6..e33e990e4185b 100644 --- a/platform/mv3/extension/_locales/sk/messages.json +++ b/platform/mv3/extension/_locales/sk/messages.json @@ -31,6 +31,10 @@ "message": "Režim filtrovania", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Nahlásiť problém na tejto webovej stránke", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Otvoriť ovládací panel", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Externé závislosti (kompatibilné s GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Nahlásiť problém s filtrom", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "supportS6P1S1": { + "message": "Aby ste dobrovoľníkov nezaťažovali duplicitnými hláseniami, overte si, či už problém nebol nahlásený.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Vyhľadať podobné hlásenia", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Adresa webovej stránky:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Webová stránka…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Vyberte položku --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Zobrazuje reklamy alebo zvyšky reklám", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Je prekrytá alebo má iné nedostatky", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detegovaný uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Má problémy súvisiace so súkromím", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Poruchy pri povolenom uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Otvára nechcené karty alebo okná", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Smeruje k badvéru a phishingu", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Označiť webovú stránku ako \"NSFW\" (“Not Safe For Work”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Vytvoriť nové hlásenie", + "description": "Text for button which open an external webpage in Support pane" + }, "firstRunSectionLabel": { "message": "Vitajte", "description": "The header text for the welcome message section" @@ -147,6 +215,10 @@ "message": "Zoznam názvov hostiteľov s vylúčeným filtrovaním", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[len názvy hostiteľov]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Správanie", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Zobraziť počet zablokovaných požiadaviek na ikone rozšírenia", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Povoliť prísne blokovanie", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Navigácia na potenciálne nežiaduce stránky sa zablokuje a ponúkne sa vám možnosť pokračovať.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Nájsť zoznamy", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Zablokovaná stránka", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite zabránil načítaniu nasledujúcej stránky:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Stránka bola zablokovaná z dôvodu zhodného filtra v{{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "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" + }, + "strictblockNoParamsPrompt": { + "message": "bez parametrov", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Naspäť", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Zatvoriť toto okno", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Už ma na túto stránku neupozorňovať", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Pokračovať", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/sl/messages.json b/platform/mv3/extension/_locales/sl/messages.json index 4bbb5e389bf08..b5d2ec8498ea7 100644 --- a/platform/mv3/extension/_locales/sl/messages.json +++ b/platform/mv3/extension/_locales/sl/messages.json @@ -31,6 +31,10 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "List of websites for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Behavior", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/so/messages.json b/platform/mv3/extension/_locales/so/messages.json index 4bbb5e389bf08..b5d2ec8498ea7 100644 --- a/platform/mv3/extension/_locales/so/messages.json +++ b/platform/mv3/extension/_locales/so/messages.json @@ -31,6 +31,10 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "List of websites for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Behavior", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/sq/messages.json b/platform/mv3/extension/_locales/sq/messages.json index 7b8c0748da091..9019b355488de 100644 --- a/platform/mv3/extension/_locales/sq/messages.json +++ b/platform/mv3/extension/_locales/sq/messages.json @@ -31,6 +31,10 @@ "message": "mënyra e filtrimit", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Raportoj problemin me uebsajtin", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Hapni panelin e kontrollit", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Programet kushtëzuese (sipas GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Raportoni problemet me filtrat", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "supportS6P1S1": { + "message": "Verifikoni a është raportuar më parë problemi që të mos i lodhni vullnetarët e tjerë me të njëjtat gjëra.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Gjej raporte të ngjashme", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Adresa e uebsajtit:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Uebsajti…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Zgjidhni --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shfaq reklama ose pjesë reklamash", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Ka mbivendosje ose parregullsi të tjera", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Zbulon uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Ka probleme me ruajtjen e privatësisë", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Punon keq kur uBO Lite është i aktivizuar", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Hap skeda ose dritare të panevojshme", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Çon te programet keqdashëse, mashtruese", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Etiketoni faqen e internetit si “NSFW” (“Not Safe For Work”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Krijoj raport të ri", + "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" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Emrat e hosteve, që nuk do të kalojnë në filtër.", + "message": "Lista e uebsajteve që nuk do të kalojnë në filtër.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[vetëm emrat e hosteve]\nshembull.com\nlojera.shembull\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Sjellja", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Shfaq numrin e kërkesave të bllokuara në ikonën e instrumenteve", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Aktivizoj bllokimin strikt", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Uebsajtet potencialisht të padëshirueshme do të bllokohen dhe do t'ju jepet mundësia për të vazhduar.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Gjej listat", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Faqe e bllokuar", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite pengoi hapjen e faqes vijuese:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Faqja u bllokua për shkak se përputhet me filtrin në {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "Faqja e bllokuar do t'ju drejtojë në një uebsajt tjetër. Në rast se pranoni do të shkoni direkt te: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "pa parametra", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Kthehem", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Mbyll dritaren", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Mos më lajmëro për këtë faqen", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Vazhdoj", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/sr/messages.json b/platform/mv3/extension/_locales/sr/messages.json index 5680a04dc5823..329b33f041768 100644 --- a/platform/mv3/extension/_locales/sr/messages.json +++ b/platform/mv3/extension/_locales/sr/messages.json @@ -31,6 +31,10 @@ "message": "режим филтрирања", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Пријавите проблем на овом веб сајту", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Отвори контролну таблу", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Спољне зависности (компатибилно са GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Пријављивање проблема са филтером", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "Пријавите проблеме са филтерима на одређеним веб сајтовима на uBlockOrigin/uAssets issue tracker. Захтева GitHub налог.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS6P1S1": { + "message": "Да не бисте оптерећивали волонтере дуплим извештајима, проверите да ли је проблем већ пријављен.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Пронађи сличне извештаје", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Адреса веб странице:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Веб страница...", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Приказује рекламе или остатке реклама", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Има преклапања или друге сметње", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Детектује uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Кварови када је uBO Lite омогућен", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Отвара нежељене картице или прозоре", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Води до лошег софтвера, „пецања\"", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "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" @@ -144,9 +212,13 @@ "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...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Понашање", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Прикажи број блокираних захтева на иконици на траци алата", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Омогући строго блокирање", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Навигација до потенцијално непожељних сајтова ће бити блокирана и биће вам понуђена опција да наставите.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Пронађи листе", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Страница је блокирана", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite је спречио учитавање следеће странице:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "без параметара", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Иди назад", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Затвори овај прозор", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Не упозоравај ме поново на ову страницу", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Настави", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/sv/messages.json b/platform/mv3/extension/_locales/sv/messages.json index 5dcbfc98a8a3f..e164490906acc 100644 --- a/platform/mv3/extension/_locales/sv/messages.json +++ b/platform/mv3/extension/_locales/sv/messages.json @@ -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 behörighetslös innehållsblockerare. Blockerar annonser, spårare, miners och mer omedelbart efter installationen.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -31,6 +31,10 @@ "message": "filtreringsläge", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Rapportera ett problem på denna webbplats", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Öppna kontrollpanelen", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Externa beroenden (GPLv3-kompatibla):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Rapportera ett filterproblem", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "supportS6P1S1": { + "message": "För att undvika att belasta volontärer med dubbletter av rapporter, kontrollera att problemet inte redan har rapporterats.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Hitta liknande rapporter", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Hemsidans adress:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Hemsidan...", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Välj en post --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Visar annonser eller rester av annonser", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Har överlägg eller andra olägenheter", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Upptäcker uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Har integritetsrelaterade problem", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Fungerar inte när uBO Lite är aktiverad", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Öppnar oönskade flikar eller fönster", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leder till skadlig programvara, nätfiske", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Märk webbsidan som “NSFW” (“Inte lämplig på jobbet”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Skapa ny rapport", + "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" @@ -147,6 +215,10 @@ "message": "Lista över värdnamn som inte kommer att filtreras", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[endast värdnamn]\nexempel.se\nspel.exempel\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Beteende", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Visa antalet blockerade förfrågningar på verktygsfältsikonen", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Aktivera strikt blockering", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Navigering till potentiellt oönskade webbplatser kommer att blockeras och du kommer att erbjudas alternativet att fortsätta.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Hitta listor", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Sidan blockerad", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite har förhindrat följande sida från att läsas in:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Sidan har blockerats på grund av ett matchande filter i {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "Den blockerade sidan vill omdirigera till en annan webbplats. Om du väljer att fortsätta skickas du direkt till: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "utan parametrar", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Gå tillbaka", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Stäng det här fönstret", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Varna mig inte igen om den här sidan", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Fortsätt", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/sw/messages.json b/platform/mv3/extension/_locales/sw/messages.json index 4bbb5e389bf08..b5d2ec8498ea7 100644 --- a/platform/mv3/extension/_locales/sw/messages.json +++ b/platform/mv3/extension/_locales/sw/messages.json @@ -31,6 +31,10 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "List of websites for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Behavior", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/ta/messages.json b/platform/mv3/extension/_locales/ta/messages.json index 4bbb5e389bf08..b5d2ec8498ea7 100644 --- a/platform/mv3/extension/_locales/ta/messages.json +++ b/platform/mv3/extension/_locales/ta/messages.json @@ -31,6 +31,10 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -144,9 +212,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "List of websites for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Behavior", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/te/messages.json b/platform/mv3/extension/_locales/te/messages.json index 00008c2bf2ac7..1dbee4ca9a2e2 100644 --- a/platform/mv3/extension/_locales/te/messages.json +++ b/platform/mv3/extension/_locales/te/messages.json @@ -31,6 +31,10 @@ "message": "వడపోత మోడ్", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "డాష్‌బోర్డ్‌ను తెరవండి", "description": "English: Click to open the dashboard" @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,6 +103,70 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -147,6 +215,10 @@ "message": "వడపోత జరగని హోస్ట్ పేర్ల జాబితా", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "ప్రవర్తన", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/th/messages.json b/platform/mv3/extension/_locales/th/messages.json index 8d523ba56d2de..fea659106cd36 100644 --- a/platform/mv3/extension/_locales/th/messages.json +++ b/platform/mv3/extension/_locales/th/messages.json @@ -16,21 +16,25 @@ "description": "English: uBO Lite — Dashboard" }, "settingsPageName": { - "message": "Settings", + "message": "การตั้งค่า", "description": "appears as tab name in dashboard" }, "aboutPageName": { - "message": "About", + "message": "เกี่ยวกับเรา", "description": "appears as tab name in dashboard" }, "aboutPrivacyPolicy": { - "message": "Privacy policy", + "message": "นโยบายความเป็นส่วนตัว", "description": "Link to privacy policy on GitHub (English)" }, "popupFilteringModeLabel": { - "message": "filtering mode", + "message": "โหมดตัวกรอง", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -48,7 +52,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAds": { - "message": "Ads", + "message": "โฆษณา", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupPrivacy": { @@ -56,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -72,7 +76,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "aboutChangelog": { - "message": "Changelog", + "message": "บันทึการเปลี่ยนแปลง", "description": "" }, "aboutCode": { @@ -99,16 +103,80 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Report a filter issue", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "สร้างรายงานใหม่", + "description": "Text for button which open an external webpage in Support pane" + }, "firstRunSectionLabel": { - "message": "Welcome", + "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.", + "message": "คุณเพิ่งติดตั้ง uBO Lite คุณสามารถเลือกโหมดการกรอง (ค่าเริ่มต้น) ที่จะใช้กับเว็บไซต์ทั้งหมดได้ที่นี่\n\nตามค่าเริ่มต้น โหมด พื้นฐาน จะถูกเลือกเนื่องจากไม่จำเป็นต้องมีสิทธิ์ในการอ่านและแก้ไขข้อมูล หากคุณไว้วางใจ uBO Lite คุณสามารถให้สิทธิ์ในการอ่านและแก้ไขข้อมูลบนเว็บไซต์ทั้งหมดได้ เพื่อเปิดใช้งานคุณสมบัติการกรองข้อมูลขั้นสูงสำหรับเว็บไซต์ทั้งหมดตามค่าเริ่มต้น", "description": "Descriptive text shown at first install time only " }, "defaultFilteringModeSectionLabel": { - "message": "Default filtering mode", + "message": "โหมดการกรองเริ่มต้น", "description": "The header text for the default filtering mode section" }, "defaultFilteringModeDescription": { @@ -120,7 +188,7 @@ "description": "Name of blocking mode 0" }, "filteringMode1Name": { - "message": "basic", + "message": "พื้นฐาน", "description": "Name of blocking mode 1" }, "filteringMode2Name": { @@ -144,19 +212,71 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "List of websites for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { - "message": "Behavior", + "message": "ลักษณะการทำงาน", "description": "The header text for the 'Behavior' section" }, "autoReloadLabel": { - "message": "Automatically reload page when changing filtering mode", + "message": "โหลดหน้าเว็บใหม่อัตโนมัติเมื่อเปลี่ยนโหมดการกรอง", "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { - "message": "Show the number of blocked requests on the toolbar icon", + "message": "แสดงจำนวนคำขอที่ถูกปิดกั้นบนไอคอนแถบเครื่องมือ", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/tr/messages.json b/platform/mv3/extension/_locales/tr/messages.json index b4e410117aedf..0fb973629fedc 100644 --- a/platform/mv3/extension/_locales/tr/messages.json +++ b/platform/mv3/extension/_locales/tr/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "İzin gerektirmeyen içerik engelleyicisi. Kurulumdan hemen sonra reklamları, izleyicileri, kripto madencilerini, ve daha fazlasını engeller.", + "message": "İzin gerektirmeyen içerik engelleyicisi. Kurulumdan hemen sonra reklamları, izleyicileri, ve daha fazlasını engeller.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -31,6 +31,10 @@ "message": "Filtreleme modu", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Bu sitedeki bir sorunu bildir", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Kontrol panelini aç", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Dış bağlılıklar (GPLv3-uyumlu):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Bir filtre sorununu bildir", + "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.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS6P1S1": { + "message": "Gönüllüleri benzer raporlar ile bezdirmemek için sorunun zaten bildirilip bildirilmediğine bakın.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Benzer raporları bul", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Web sayfasının adresi:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Web sayfası…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Bir girdi seçin --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Reklamlar veya reklam artıkları gösteriyor", + "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", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "uBO Lite tespit ediliyor", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Gizlilikle ilgili sorunları var", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "uBO Lite kullanımdayken sayfa bozuluyor ", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "İstenmeyen sekme veya pencereler açıyor", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Kötü niyetli yazılıma yönlendiriyor, oltalama", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Sayfayı “NSFW” (“iş için güvenli değil”) olarak işaretle", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "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" @@ -147,16 +215,68 @@ "message": "Filtreleme yapılmayacak alan alarının listesi", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[sadece ana bilgisayar adları]\nörnek.com\noyunlar.site\n…", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Davranış", "description": "The header text for the 'Behavior' section" }, "autoReloadLabel": { - "message": "Filtreleme modu değiştirildiğinde sayfayı yenile", + "message": "Filtreleme modunu değiştirirken sayfayı otomatik olarak yenile", "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { "message": "Engellenen isteklerin sayısını araç çubuğu simgesinde göster", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Sıkı engellemeyi kullanıma al", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "İstenmeyebilecek sitelere giriş engellenecek ve devam edip etmeyeceğiniz size sorulacak.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Liste bul", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Sayfa engellendi", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBo Lite aşağıdaki sayfaların yüklenmesini engelledi:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Bu sayfa {{listname}} içindeki bir süzgece takıldığı için engellenmiştir.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "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" + }, + "strictblockNoParamsPrompt": { + "message": "değişkensiz", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Geri git", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Bu pencereyi kapat", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Bu site için beni bir daha uyarma", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Devam et", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/uk/messages.json b/platform/mv3/extension/_locales/uk/messages.json index 5bf1a04b50d6e..c6d372980a1e6 100644 --- a/platform/mv3/extension/_locales/uk/messages.json +++ b/platform/mv3/extension/_locales/uk/messages.json @@ -31,6 +31,10 @@ "message": "режим фільтрації", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Повідомити про помилку на цьому вебсайті", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Відкрити панель керування", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "Зовнішні залежності (Сумісні з GPLv3)", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Повідомити про ваду фільтра", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "Повідомляйте про вади з фільтрами на конкретних вебсайтах у відстежувач помилок uBlockOrigin/uAssets. Потрібен обліковий запис GitHub.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS6P1S1": { + "message": "Щоб не обтяжувати волонтерів повторюваними звітами, переконайтеся, що про проблему ще не повідомлялося.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Знайти подібні звіти", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Адреса вебсторінки:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Вебсторінка...", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Указати проблему --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "З'являється реклама або залишки оголошень", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Накладання або інші прикрощі", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Виявляє uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Пов'язані з приватністю проблеми", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Вади коли uBO Lite ввімкнено", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Відкриває небажані вкладки або вікна", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Веде до шкідливого ПЗ, фішингу", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "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" @@ -140,13 +208,17 @@ "description": "This describes the 'optimal' filtering mode" }, "completeFilteringModeDescription": { - "message": "Розширена мережева фільтрація плюс специфічна та загальна розширена фільтрація з вибраних списків фільтрів.\n\nПотребує широкого дозволу на читання та зміну даних на всіх сайтах.\n\nЗагальна розширена фільтрація може призвести до збільшення використання ресурсів веб-сторінки.", + "message": "Розширена мережева фільтрація плюс специфічна та загальна розширена фільтрація з вибраних списків фільтрів.\n\nПотребує розширених дозволів на читання та зміну даних на всіх сайтах.\n\nЗагальна розширена фільтрація може призвести до збільшення використання ресурсів вебсторінкою.", "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...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Поведінка", "description": "The header text for the 'Behavior' section" @@ -156,7 +228,55 @@ "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { - "message": "Показувати кількість заблокованих запитів на піктограмі на панелі інструментів", + "message": "Показувати кількість заблокованих запитів на піктограмі панелі інструментів", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Увімкнути суворе блокування", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Перехід до потенційно небажаних сайтів буде заблоковано, та вам буде запропоновано можливість продовжити", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Знайти списки", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Сторінку заблоковано", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite заблокував завантаження наступних сторінок:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Сторінку заблоковано, бо вона відповідає фільтру в {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "Заблокована сторінка хоче переадресувати на інший сайт. Якщо ви вирішите продовжити, ви перейдете безпосередньо на: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "без параметрів", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Повернутися", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Закрити це вікно", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Більше не попереджати мене про цей сайт", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Продовжити", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/ur/messages.json b/platform/mv3/extension/_locales/ur/messages.json index 2705d513fd105..97cf4fd512537 100644 --- a/platform/mv3/extension/_locales/ur/messages.json +++ b/platform/mv3/extension/_locales/ur/messages.json @@ -28,63 +28,67 @@ "description": "Link to privacy policy on GitHub (English)" }, "popupFilteringModeLabel": { - "message": "filtering mode", + "message": "فلٹرنگ موڈ", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Report an issue on this website", + "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": { - "message": "Ads", + "message": "اشتہارات", "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 domains", + "message": "Malware protection, security", "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'" }, "aboutChangelog": { - "message": "Changelog", + "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": { @@ -92,39 +96,103 @@ "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", + "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" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Address of the webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "The webpage…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Pick an entry --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Shows ads or ad leftovers", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Has overlays or other nuisances", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detects uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Has privacy-related issues", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Malfunctions when uBO Lite is enabled", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Opens unwanted tabs or windows", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Leads to badware, 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”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Create new report", + "description": "Text for button which open an external webpage in Support pane" + }, "firstRunSectionLabel": { - "message": "Welcome", + "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.", + "message": "آپ نے ابھی یو بی او لائٹ انسٹال کیا ہے۔ یہاں آپ تمام ویب سائٹس پر استعمال کرنے کے لیے ڈیفالٹ فلٹرنگ موڈ کا انتخاب کر سکتے ہیں۔\n\nپہلے سے طے شدہ طور پر، بنیادی موڈ کو منتخب کیا جاتا ہے کیونکہ اسے ڈیٹا کو پڑھنے اور اس میں ترمیم کرنے کی اجازت کی ضرورت نہیں ہوتی ہے۔ اگر آپ کو uBO Lite پر بھروسہ ہے، تو آپ اسے تمام ویب سائٹس پر ڈیٹا کو پڑھنے اور اس میں ترمیم کرنے کی وسیع اجازت دے سکتے ہیں تاکہ تمام ویب سائٹس کے لیے پہلے سے طے شدہ فلٹرنگ کی مزید جدید صلاحیتوں کو فعال کیا جا سکے۔", "description": "Descriptive text shown at first install time only " }, "defaultFilteringModeSectionLabel": { - "message": "Default filtering mode", + "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": { - "message": "basic", + "message": "بنیادی", "description": "Name of blocking mode 1" }, "filteringMode2Name": { - "message": "optimal", + "message": "بہترین", "description": "Name of blocking mode 2" }, "filteringMode3Name": { @@ -132,31 +200,83 @@ "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 hostnames for which no filtering will take place.", + "message": "میزبان ناموں کی فہرست جن کے لیے کوئی فلٹرنگ نہیں ہوگی۔", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { - "message": "Behavior", + "message": "رویہ", "description": "The header text for the 'Behavior' section" }, "autoReloadLabel": { - "message": "Automatically reload page when changing filtering mode", + "message": "فلٹرنگ موڈ تبدیل کرتے وقت صفحہ خودکار طور پر دوبارہ لوڈ کریں۔", "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { - "message": "Show the number of blocked requests on the toolbar icon", + "message": "ٹول بار کے آئیکن پر بلاک شدہ درخواستوں کی تعداد دکھائیں۔", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/vi/messages.json b/platform/mv3/extension/_locales/vi/messages.json index 9f796fc5d5ffe..069791bb6ec7e 100644 --- a/platform/mv3/extension/_locales/vi/messages.json +++ b/platform/mv3/extension/_locales/vi/messages.json @@ -31,6 +31,10 @@ "message": "chế độ lọc", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "Báo cáo lỗi trên trang này", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Mở bảng điều khiển", "description": "English: Click to open the dashboard" @@ -40,7 +44,7 @@ "description": "Label to be used to show popup panel sections" }, "popupLessButton": { - "message": "Ít hơn", + "message": "Thu gọn", "description": "Label to be used to hide popup panel sections" }, "3pGroupDefault": { @@ -52,7 +56,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupPrivacy": { - "message": "Riêng tư", + "message": "Bảo mật", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { @@ -80,7 +84,7 @@ "description": "English: Source code (GPLv3)" }, "aboutContributors": { - "message": "Những người đóng góp", + "message": "Người đóng góp", "description": "English: Contributors" }, "aboutSourceCode": { @@ -99,6 +103,70 @@ "message": "Các phụ thuộc bên ngoài (tương thích GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "Báo cáo lỗi bộ lọc cụ thể", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "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" + }, + "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" + }, + "supportFindSpecificButton": { + "message": "Tìm các báo cáo tương tự", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Địa chỉ của trang web:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Trang web…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Chọn một mục --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Hiện quảng cáo hoặc vùng chứa quảng cáo", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Có lớp phủ hoặc những phiền toái khác", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Phát hiện uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Có các cấn đề về quyền riêng tư", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "Trục trặc khi bật uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Xuất hiện các tab và cửa sổ ngoài mong muốn", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Dẫn đến phần mềm độc hại, lừa đảo", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Đánh dấu trang web là “NSFW” (“Không an toàn cho công việc”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "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" @@ -147,6 +215,10 @@ "message": "Danh sách tên máy chủ sẽ không được lọc", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames only]\nexample.com\ngames.example", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Hành vi", "description": "The header text for the 'Behavior' section" @@ -158,5 +230,53 @@ "showBlockedCountLabel": { "message": "Hiện số lượng yêu cầu bị chặn trên biểu tượng thanh công cụ", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Enable strict blocking", + "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.", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Page blocked", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite has prevented the following page from loading:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "The page was blocked because of a matching filter in {{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}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "without parameters", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Go back", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Close this window", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Don't warn me again about this site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Proceed", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/zh_CN/messages.json b/platform/mv3/extension/_locales/zh_CN/messages.json index ffbbf9c03badb..136a6284673da 100644 --- a/platform/mv3/extension/_locales/zh_CN/messages.json +++ b/platform/mv3/extension/_locales/zh_CN/messages.json @@ -31,6 +31,10 @@ "message": "过滤模式", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "反馈该网站上的问题", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "在仪表板中", "description": "English: Click to open the dashboard" @@ -99,6 +103,70 @@ "message": "外部依赖(与 GPLv3 协议兼容):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "报告过滤问题", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "将特定网站的过滤问题报告给uBlockOrigin/uAssets issue tracker需要有 GitHub 账户。", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS6P1S1": { + "message": "请确认该问题未曾上报,以避免加重志愿者负担。", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "找到相似报告", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "网页地址:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "网页...", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- 选择一个条目 --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "显示广告或残留广告", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "存在遮盖或类似问题", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "检测到 uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "存在隐私相关问题", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "启用 uBO Lite 时发生故障", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "打开了不想要的标签页或窗口", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "导致恶意软件、网络钓鱼", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "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" @@ -147,6 +215,10 @@ "message": "不进行过滤的主机名列表", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[域名]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "操作设置", "description": "The header text for the 'Behavior' section" @@ -156,7 +228,55 @@ "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { - "message": "在工具栏图标上显示已拦截的请求数", + "message": "在工具栏图标上显示拦截请求数", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "开启严格拦截", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "导航至潜在不良网站的操作将被拦截,并且您将可以选择继续前往。", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "查找列表", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "被拦截的页面", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite 已阻止了以下页面的加载:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "该页面由于 {{listName}} 中的匹配过滤器而被阻止。", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "被屏蔽的页面希望重定向到另一个网站。如果您选择继续,将直接导航到:{{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "不含参数", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "返回", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "关闭此窗口", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "不要再警告我关于这个网站了", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "继续", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/_locales/zh_TW/messages.json b/platform/mv3/extension/_locales/zh_TW/messages.json index 99ebc6263ea99..d76680e6644f1 100644 --- a/platform/mv3/extension/_locales/zh_TW/messages.json +++ b/platform/mv3/extension/_locales/zh_TW/messages.json @@ -31,6 +31,10 @@ "message": "過濾模式", "description": "Label in the popup panel for the current filtering mode" }, + "popupTipReport": { + "message": "回報網站問題", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "開啟控制台", "description": "English: Click to open the dashboard" @@ -96,15 +100,79 @@ "description": "Link text to uBO's own filter lists repo" }, "aboutDependencies": { - "message": "外部相依套件(與 GPLv3 相容):", + "message": "外部依存套件(相容 GPLv3):", "description": "Shown in the About pane" }, + "supportS6H": { + "message": "回報過濾規則問題", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "將特定網站的過濾器問題回報至 uBlockOrigin/uAssets 議題追蹤器需要 GitHub 帳號。.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS6P1S1": { + "message": "為免增加志願者的負擔,請先確認該問題尚未被報告。", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "尋找類似報告", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "網址:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "網頁……", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- 挑選一種情況 --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "會顯示廣告或殘留空位", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "有覆蓋物或其他滋擾物", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "偵測到 uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "存在隱私問題", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option5": { + "message": "開啟 uBO Lite 的時候運作異常", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "會開啟不需要的分頁或視窗", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "導致惡意軟體、網路釣魚", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "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": "您剛安裝了 uBO Lite。您可以在此處選擇要在所有網站上使用的預設過濾模式。\n\n預設情況下將會選取基礎模式,因為其不需要讀取與變更資料的權限。若您信任 uBO Lite,您可以給予其讀取並變更在所有網站上資料的廣泛權限,以便為所有網站啟用更進階的過濾功能。", + "message": "您剛安裝了 uBO Lite。您可以在此處選擇會套用在所有網站上的預設過濾模式。\n\n預設情況下,會使用基礎模式,因為其不需要讀取與變更資料的權限。若您信任 uBO Lite,您可以授予其讀取並變更在所有網站上資料的廣泛權限,以便為所有網站啟用進階過濾功能。", "description": "Descriptive text shown at first install time only " }, "defaultFilteringModeSectionLabel": { @@ -112,7 +180,7 @@ "description": "The header text for the default filtering mode section" }, "defaultFilteringModeDescription": { - "message": "預設過濾模式將被每個網站的過濾模式覆寫。您可以根據在該網站上最有效的模式為任何指定的網站調整過濾模式。每種模式都有其優缺點。", + "message": "預設過濾模式將被每個網站的過濾模式覆寫。你可以根據每個網站的情況,調整該網站的過濾模式,以選擇最適合的模式。每種模式都有其優缺點。", "description": "This describes the default filtering mode setting" }, "filteringMode0Name": { @@ -124,7 +192,7 @@ "description": "Name of blocking mode 1" }, "filteringMode2Name": { - "message": "最佳化", + "message": "最佳", "description": "Name of blocking mode 2" }, "filteringMode3Name": { @@ -136,27 +204,79 @@ "description": "This describes the 'basic' filtering mode" }, "optimalFilteringModeDescription": { - "message": "進階網路過濾以及來自選定過濾條件清單的特定擴展過濾條件。\n\n需要在所有網站上讀取並變更資料的廣泛權限。", + "message": "進階網路過濾以及來自選定過濾條件清單的特定擴展過濾。\n\n需要廣泛的權限以讀取和修改所有網站的數據。", "description": "This describes the 'optimal' filtering mode" }, "completeFilteringModeDescription": { - "message": "進階網路過濾以及來自選定過濾條件清單的特定與通用擴展過濾條件。\n\n需要在所有網站上讀取並變更資料的廣泛權限。\n\n通用擴展過濾可能會導致更高的網頁資源使用率。", + "message": "進階網路過濾加上來自選定過濾清單的特定及通用擴展過濾。\n\n需要廣泛的權限以讀取和修改所有網站的數據。\n\n通用擴展過濾可能導致網頁資源使用量增加。", "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...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "行為", "description": "The header text for the 'Behavior' section" }, "autoReloadLabel": { - "message": "變更過濾模式時自動重新載入頁面", + "message": "變更過濾模式時,自動重新載入", "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { - "message": "在工具列圖示上顯示被阻擋的連線請求的數量", + "message": "在工具列圖示上顯示被阻擋的網路請求數量", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "啟用嚴格阻擋", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "將會阻擋前往潛在不良網站的請求,您可以選擇繼續。", + "description": "Label for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "尋找清單", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "已封鎖頁面", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite 已防止下列頁面載入:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "由於在 {{listname}} 中有符合的過濾條件,因此該頁面被封鎖。", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "被阻擋的頁面試圖重定向到另一個網站。如果您選擇繼續,將直接導航至:{{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "不帶參數", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "返回", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "關閉此視窗", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "不要再顯示關於此網站的警告", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "繼續", + "description": "A button to navigate to the blocked page" } } diff --git a/platform/mv3/extension/css/dashboard-common.css b/platform/mv3/extension/css/dashboard-common.css index 41d641621e125..7abaeb5664dd0 100644 --- a/platform/mv3/extension/css/dashboard-common.css +++ b/platform/mv3/extension/css/dashboard-common.css @@ -1,3 +1,15 @@ +body { + align-items: center; + box-sizing: border-box; + display: flex; + flex-direction: column; + max-height: 100vh; + padding: 0 var(--default-gap-xxsmall); + } +body > * { + width: min(640px, 100%); + } + h2, h3 { margin: 1em 0; } @@ -7,9 +19,11 @@ h2 { h3 { font-size: 16px; } + a { text-decoration: none; } + .fa-icon.info { color: var(--info0-ink); fill: var(--info0-ink); diff --git a/platform/mv3/extension/css/dashboard.css b/platform/mv3/extension/css/dashboard.css index e98bcc9a40497..b7aa5adeee110 100644 --- a/platform/mv3/extension/css/dashboard.css +++ b/platform/mv3/extension/css/dashboard.css @@ -1,12 +1,3 @@ -body { - align-items: center; - box-sizing: border-box; - display: flex; - flex-direction: column; - } -body > * { - width: min(640px, 100%); - } #dashboard-nav { background-color: var(--surface-1); border: 0; @@ -16,9 +7,6 @@ body > * { flex-wrap: wrap; overflow-x: hidden; padding: 0; - position: sticky; - top: 0; - z-index: 100; } .tabButton { background-color: transparent; @@ -42,6 +30,7 @@ body > * { } body[data-pane="settings"] #dashboard-nav .tabButton[data-pane="settings"], +body[data-pane="rulesets"] #dashboard-nav .tabButton[data-pane="rulesets"], 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); @@ -51,8 +40,11 @@ body[data-pane="about"] #dashboard-nav .tabButton[data-pane="about"] { body > section { display: none; + overflow: auto; + padding-bottom: 8rem; } body[data-pane="settings"] > section[data-pane="settings"], +body[data-pane="rulesets"] > section[data-pane="rulesets"], body[data-pane="about"] > section[data-pane="about"] { display: block; } diff --git a/platform/mv3/extension/css/filtering-mode.css b/platform/mv3/extension/css/filtering-mode.css index fecb1ac3cf406..f6ed7783197bc 100644 --- a/platform/mv3/extension/css/filtering-mode.css +++ b/platform/mv3/extension/css/filtering-mode.css @@ -13,7 +13,7 @@ border-radius: 30% 15% / 15% 30%; height: 100%; position: absolute; - width: 25%; + width: calc(25% + 2px); z-index: 10; } @@ -39,12 +39,18 @@ .filteringModeSlider span[data-level] { background-color: var(--accent-surface-1); + border: 1px solid var(--accent-surface-1); + box-sizing: border-box; display: inline-flex; height: 30%; margin-left: 1px; width: 25%; } +.filteringModeSlider span[data-level]:first-of-type { + margin-left: 0; + } + .filteringModeSlider.moving span[data-level] { pointer-events: none; } @@ -53,13 +59,13 @@ left: 0; } .filteringModeSlider[data-level="1"] .filteringModeButton { - left: 25%; + left: calc(25% - 1px); } .filteringModeSlider[data-level="2"] .filteringModeButton { - left: 50%; + left: calc(50% - 1px); } .filteringModeSlider[data-level="3"] .filteringModeButton { - left: 75%; + left: calc(75% - 1px); } [dir="rtl"] .filteringModeSlider[data-level="0"] .filteringModeButton { left: 75%; @@ -77,14 +83,17 @@ .filteringModeSlider[data-level="0"] span[data-level] { background-color: var(--surface-2); + border-color: var(--surface-2); } .filteringModeSlider[data-level="1"] span[data-level]:nth-of-type(1) ~ span[data-level] { background-color: var(--surface-2); + border-color: var(--surface-2); } .filteringModeSlider[data-level="2"] span[data-level]:nth-of-type(2) ~ span[data-level] { background-color: var(--surface-2); + border-color: var(--surface-2); } .filteringModeSlider[data-level]:not(.moving) span[data-level]:hover { diff --git a/platform/mv3/extension/css/matched-rules.css b/platform/mv3/extension/css/matched-rules.css new file mode 100644 index 0000000000000..9db4d9c73f0fa --- /dev/null +++ b/platform/mv3/extension/css/matched-rules.css @@ -0,0 +1,28 @@ + +#matchedEntries { + display: flex; + flex-direction: column; + font-family: monospace; + font-size: small; + white-space: pre-wrap; + word-break: break-all; +} + +.matchInfo { + display: flex; + flex-wrap: nowrap; +} + +.matchInfo:nth-of-type(2n) { + background-color: lightgray; +} + +.requestInfo { + border-inline-end: 1px dotted black; + padding-inline-end: 0.5em; + width: 25vw; +} + +.ruleInfo { + padding-inline-start: 0.5em; +} diff --git a/platform/mv3/extension/css/popup.css b/platform/mv3/extension/css/popup.css index 385a051652f82..cc6824674a18a 100644 --- a/platform/mv3/extension/css/popup.css +++ b/platform/mv3/extension/css/popup.css @@ -63,6 +63,13 @@ hr { font-weight: 600; } +body[data-forbid~="filteringMode"] .filteringModeSlider { + pointer-events: none; + } +body[data-forbid~="dashboard"] #gotoDashboard { + display: none; + } + #filteringModeText { color: var(--ink-3); margin: var(--default-gap-small); diff --git a/platform/mv3/extension/css/settings.css b/platform/mv3/extension/css/settings.css index 2e727fc0e33ab..237fb8191984e 100644 --- a/platform/mv3/extension/css/settings.css +++ b/platform/mv3/extension/css/settings.css @@ -1,11 +1,5 @@ -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } - } -legend { - color: var(--ink-3); - font-size: var(--font-size-smaller); - padding: var(--default-gap-xxsmall); +body.loading { + visibility: hidden; } body .firstRun { display: none; @@ -15,19 +9,36 @@ body.firstRun .firstRun { display: block; padding: 8px; } +body .firstRun > *:first-child { + margin-top: 0; + } +body .firstRun > *:last-child { + margin-bottom: 0; + } h3 { margin: 1em 0; } -p { - white-space: pre-line; + +label + legend { + color: color-mix(in srgb, currentColor 69%, transparent); + font-size: var(--font-size-smaller); + margin-inline-start: var(--default-gap-large); } -section > div { - padding: 0 var(--default-gap-xxsmall); +body[data-forbid~="dashboard"] #dashboard-nav [data-pane="settings"], +body[data-forbid~="dashboard"] section[data-pane="settings"], +body[data-forbid~="dashboard"] #dashboard-nav [data-pane="rulesets"], +body[data-forbid~="dashboard"] section[data-pane="rulesets"] { + display: none; + } +body[data-forbid~="filteringMode"] section[data-pane="settings"] > div:has(> h3[data-i18n="defaultFilteringModeSectionLabel"]), +body[data-forbid~="filteringMode"] section[data-pane="settings"] > div:has(> h3[data-i18n="filteringMode0Name"]) { + display: none; } -#showBlockedCount:has(input[type="checkbox"][disabled]) { - opacity: 0.5; +label:has(input[type="checkbox"][disabled]), +label:has(input[type="checkbox"][disabled]) + legend { + filter: var(--checkbox-disabled-filter); } #defaultFilteringMode { @@ -82,85 +93,113 @@ h3[data-i18n="filteringMode0Name"]::first-letter { width: 100%; } -#lists { - margin: 0.5em 0 0 0; - padding: 0; +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; } -.groupEntry:not([data-groupkey="user"]) .geDetails::before { - color: var(--ink-3); - content: '\2212'; - font-family: monospace; - font-size: large; - margin-inline-end: 0.25em; - -webkit-margin-end: 0.25em; +section[data-pane="rulesets"] > div:first-of-type > p:first-of-type { + margin-top: 0; + } +section[data-pane="rulesets"] > div:first-of-type > p:last-of-type { + margin-bottom: 0; } -.groupEntry.hideUnused:not([data-groupkey="user"]) .geDetails::before { - content: '+'; +.listEntry { + display: flex; + flex-direction: column; } -.groupEntry { - margin: 0.5em 0; +.listEntry[data-nodeid] > .detailbar .listExpander { + cursor: pointer; + top: 2px; } -.groupEntry .geDetails { +.listEntry[data-role="rootnode"] > .detailbar, +.listEntry[data-nodeid] > .detailbar .count { cursor: pointer; } -.groupEntry .geName { +.listEntry[data-role="rootnode"] > .detailbar > *:not(.listExpander) { pointer-events: none; } -.groupEntry .geCount { +.listEntry .detailbar .count { + align-self: flex-end; color: var(--ink-3); - font-size: 90%; + font-size: small; pointer-events: none; } .listEntries { - margin-inline-start: 0.6em; - -webkit-margin-start: 0.6em; + display: flex; + flex-direction: column; + } +.listEntry:not([data-role="rootnode"]) > .listEntries { + margin-inline-start: var(--checkbox-size); + } +.listEntry.hideUnused > .listEntries > .listEntry:not(.isDefault):has(> .detailbar input:not(:checked)) { + display: none; } -.groupEntry:not([data-groupkey="user"]) .listEntry:not(.isDefault).unused { +.listEntry.fromAdmin:has(> .detailbar input[disabled]:not(:checked)) { display: none; } .listEntry > * { - margin-left: 0; - margin-right: 0; unicode-bidi: embed; } -.listEntry .listname { +.listEntry h3 { + display: inline-block; + margin: 0; + } +.listEntry > .detailbar { + align-items: center; + display: inline-flex; + margin: calc(var(--default-gap-xsmall) / 2 + var(--default-gap-xxsmall) / 2) 0; white-space: nowrap; } +.listEntry > .detailbar > *:not(:first-child) { + margin-inline-start: var(--default-gap-xxsmall); + } +.listEntry[data-nodeid="default"] > .detailbar > .listExpander { + display: none; + } +.listEntry > .detailbar > .listExpander svg { + transform: rotate(180deg); + transform-origin: 50%; + } +.listEntry.hideUnused > .detailbar > .listExpander svg { + transform: rotate(90deg); + } +.listEntry .checkbox:has(input[disabled]), +.listEntry .checkbox:has(input[disabled]) ~ span { + filter: var(--checkbox-disabled-filter); + } .listEntry a, .listEntry .fa-icon { color: var(--info0-ink); fill: var(--info0-ink); - display: none; font-size: 120%; - margin: 0 0.2em 0 0; } .listEntry .fa-icon:hover { transform: scale(1.25); } -.listEntry .content { - display: inline-flex; - } -.listEntry a.towiki { - display: inline-flex; - } -.listEntry.support a.support { - display: inline-flex; - } -.listEntry.mustread a.mustread { - color: var(--info1-ink); - fill: var(--info1-ink); - display: inline-flex; - } -.listEntry .status { - cursor: default; +.listEntry .iconbar a.support[href="#"] { display: none; -} + } -body.noMoreRuleset .listEntry:not(.checked) { +body.noMoreRuleset .listEntry:has(> .detailbar input:not(:checked)) { opacity: 0.5; pointer-events: none; } +#lists.searchMode > .listEntries .listEntries, +#lists.searchMode > .listEntries .listEntry.searchMatch { + display: flex !important; + } +#lists.searchMode > .listEntries .listEntry { + display: none; + } +#lists.searchMode > .listEntries .listExpander { + visibility: hidden; + } + /* touch-screen devices */ :root.mobile .listEntry .fa-icon { font-size: 120%; diff --git a/platform/mv3/extension/css/strictblock.css b/platform/mv3/extension/css/strictblock.css new file mode 100644 index 0000000000000..5a459446434a3 --- /dev/null +++ b/platform/mv3/extension/css/strictblock.css @@ -0,0 +1,158 @@ +/** + uBlock Origin - a browser extension to block requests. + Copyright (C) 2018-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 +*/ + +body { + display: flex; + padding: var(--default-gap-xxlarge) var(--default-gap-small); + justify-content: center; + } +:root.mobile body { + padding: var(--default-gap-small); + } +body.loading { + visibility: hidden; + } + +#rootContainer { + width: min(100%, 640px); + } +#rootContainer > * { + margin: 0 0 var(--default-gap-xxlarge) 0; + } +:root.mobile #rootContainer > * { + margin-bottom: var(--default-gap-xlarge); + } + +p { + margin: 0.5em 0; + } +a { + text-decoration: none; + } +q { + font-weight: bold; + } +.code { + font-size: var(--font-size-smaller); + word-break: break-all; + } +#warningSign { + color: var(--accent-surface-1); + fill: var(--accent-surface-1); + font-size: 96px; + line-height: 1; + width: 100%; + } +:root.mobile #warningSign { + font-size: 64px; + } +#theURL { + color: var(--ink-2); + padding: 0; + } +#theURL > * { + margin: 0; + } +#theURL > p { + position: relative; + z-index: 10; + } +#theURL > p > span:first-of-type { + display: block; + max-height: 6lh; + overflow-y: auto; + } +:root.mobile #theURL > p > span:first-of-type { + max-height: 3lh; + } +#theURL #toggleParse { + background-color: transparent; + top: 100%; + box-sizing: border-box; + color: var(--ink-3); + fill: var(--ink-3); + cursor: pointer; + font-size: 1.2rem; + padding: var(--default-gap-xxsmall); + position: absolute; + transform: translate(0, -50%); + } +#theURL:not(.collapsed) #toggleParse > span:first-of-type { + display: none; + } +#theURL.collapsed #toggleParse > span:last-of-type { + display: none; + } +body[dir="ltr"] #toggleParse { + right: 0; + } +body[dir="rtl"] #toggleParse { + left: 0; + } +#theURL > p:hover #toggleParse { + transform: translate(0, -50%) scale(1.15); + } +#parsed { + background-color: var(--surface-1); + border: 4px solid var(--surface-2); + font-size: small; + overflow-x: auto; + padding: var(--default-gap-xxsmall); + text-align: initial; + text-overflow: ellipsis; + } +#theURL.collapsed > #parsed { + display: none; + } +#parsed ul, #parsed li { + list-style-type: none; + } +#parsed li { + white-space: nowrap; + } +#parsed span { + display: inline-block; + } +#parsed span:first-of-type { + font-weight: bold; + } + +#urlskip a { + display: block; + overflow-y: auto; + } + +#actionContainer { + display: flex; + justify-content: space-between; + } +:root.mobile #actionContainer { + justify-content: center; + display: flex; + flex-direction: column; + } +#actionContainer > button { + margin-bottom: 2rem + } + +/* Small-screen devices */ +:root.mobile button { + width: 100%; + } diff --git a/platform/mv3/extension/dashboard.html b/platform/mv3/extension/dashboard.html index d2dc918d980db..8ef9799041a2e 100644 --- a/platform/mv3/extension/dashboard.html +++ b/platform/mv3/extension/dashboard.html @@ -16,11 +16,12 @@ - +
@@ -87,37 +88,24 @@

+

+

_

-

+

- + + +
-

-
-

-
-
-
-
-
- -
-
-
-
-
- +

+

+
@@ -146,6 +134,32 @@

+
+
+
+ + + home + + +
+ + +
diff --git a/platform/mv3/extension/js/admin.js b/platform/mv3/extension/js/admin.js new file mode 100644 index 0000000000000..8a6b91fb77765 --- /dev/null +++ b/platform/mv3/extension/js/admin.js @@ -0,0 +1,121 @@ +/******************************************************************************* + + 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 { + adminRead, + localRead, localWrite, + sessionRead, sessionWrite, +} from './ext.js'; + +import { + enableRulesets, + getRulesetDetails, +} from './ruleset-manager.js'; + +import { + getTrustedSites, + readFilteringModeDetails, +} from './mode-manager.js'; + +import { broadcastMessage } from './utils.js'; +import { dnr } from './ext.js'; +import { registerInjectables } from './scripting-manager.js'; +import { rulesetConfig } from './config.js'; +import { ubolLog } from './debug.js'; + +/******************************************************************************/ + +const adminSettings = { + keys: new Set(), + timer: undefined, + change(key) { + this.keys.add(key); + if ( this.timer !== undefined ) { return; } + this.timer = self.setTimeout(( ) => { + this.timer = undefined; + this.process(); + }, 127); + }, + async process() { + if ( this.keys.has('rulesets') ) { + ubolLog('admin setting "rulesets" changed'); + await enableRulesets(rulesetConfig.enabledRulesets); + await registerInjectables(); + const results = await Promise.all([ + getAdminRulesets(), + dnr.getEnabledRulesets(), + ]); + const [ adminRulesets, enabledRulesets ] = results; + broadcastMessage({ adminRulesets, enabledRulesets }); + } + if ( this.keys.has('noFiltering') ) { + ubolLog('admin setting "noFiltering" changed'); + await readFilteringModeDetails(true); + const trustedSites = await getTrustedSites(); + broadcastMessage({ trustedSites: Array.from(trustedSites) }); + } + this.keys.clear(); + } +}; + +/******************************************************************************/ + +export async function getAdminRulesets() { + const adminList = await adminReadEx('rulesets'); + const adminRulesets = new Set(Array.isArray(adminList) && adminList || []); + 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; } + adminRulesets.add(`-${ruleset.id}`); + } + } + return Array.from(adminRulesets); +} + +/******************************************************************************/ + +export async function adminReadEx(key) { + let cacheValue; + const session = await sessionRead(`admin_${key}`); + if ( session ) { + cacheValue = session.data; + } else { + const local = await localRead(`admin_${key}`); + if ( local ) { + cacheValue = local.data; + } + } + adminRead(key).then(async value => { + 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); + }); + return cacheValue; +} + +/******************************************************************************/ diff --git a/platform/mv3/extension/js/background.js b/platform/mv3/extension/js/background.js index e65775e9db7f8..ce8c0ea93bd10 100644 --- a/platform/mv3/extension/js/background.js +++ b/platform/mv3/extension/js/background.js @@ -19,104 +19,71 @@ Home: https://github.com/gorhill/uBlock */ -/******************************************************************************/ +import { + MODE_BASIC, + MODE_OPTIMAL, + getDefaultFilteringMode, + getFilteringMode, + getTrustedSites, + setDefaultFilteringMode, + setFilteringMode, + setTrustedSites, + syncWithBrowserPermissions, +} from './mode-manager.js'; import { adminRead, browser, dnr, - localRead, localWrite, + localRead, localRemove, localWrite, runtime, - sessionRead, sessionWrite, + windows, } from './ext.js'; import { - broadcastMessage, - ubolLog, -} from './utils.js'; + adminReadEx, + getAdminRulesets, +} from './admin.js'; import { - defaultRulesetsFromLanguage, enableRulesets, + excludeFromStrictBlock, getEnabledRulesetsDetails, getRulesetDetails, + patchDefaultRulesets, + setStrictBlockMode, updateDynamicRules, } from './ruleset-manager.js'; import { - getDefaultFilteringMode, - getFilteringMode, - getTrustedSites, - setDefaultFilteringMode, - setFilteringMode, - setTrustedSites, - syncWithBrowserPermissions, -} from './mode-manager.js'; + getMatchedRules, + isSideloaded, + toggleDeveloperMode, + ubolLog, +} from './debug.js'; import { - registerInjectables, -} from './scripting-manager.js'; + loadRulesetConfig, + process, + rulesetConfig, + saveRulesetConfig, +} from './config.js'; -/******************************************************************************/ +import { broadcastMessage } from './utils.js'; +import { registerInjectables } from './scripting-manager.js'; -const rulesetConfig = { - version: '', - enabledRulesets: [ 'default' ], - autoReload: true, - showBlockedCount: true, -}; +/******************************************************************************/ const UBOL_ORIGIN = runtime.getURL('').replace(/\/$/, ''); const canShowBlockedCount = typeof dnr.setExtensionActionOptions === 'function'; -let firstRun = false; -let wakeupRun = false; - /******************************************************************************/ function getCurrentVersion() { return runtime.getManifest().version; } -async function loadRulesetConfig() { - let data = await sessionRead('rulesetConfig'); - if ( data ) { - rulesetConfig.version = data.version; - rulesetConfig.enabledRulesets = data.enabledRulesets; - rulesetConfig.autoReload = typeof data.autoReload === 'boolean' - ? data.autoReload - : true; - rulesetConfig.showBlockedCount = typeof data.showBlockedCount === 'boolean' - ? data.showBlockedCount - : true; - wakeupRun = true; - return; - } - data = await localRead('rulesetConfig'); - if ( data ) { - rulesetConfig.version = data.version; - rulesetConfig.enabledRulesets = data.enabledRulesets; - rulesetConfig.autoReload = typeof data.autoReload === 'boolean' - ? data.autoReload - : true; - rulesetConfig.showBlockedCount = typeof data.showBlockedCount === 'boolean' - ? data.showBlockedCount - : true; - sessionWrite('rulesetConfig', rulesetConfig); - return; - } - rulesetConfig.enabledRulesets = await defaultRulesetsFromLanguage(); - sessionWrite('rulesetConfig', rulesetConfig); - localWrite('rulesetConfig', rulesetConfig); - firstRun = true; -} - -async function saveRulesetConfig() { - sessionWrite('rulesetConfig', rulesetConfig); - return localWrite('rulesetConfig', rulesetConfig); -} - /******************************************************************************/ async function hasGreatPowers(origin) { @@ -126,7 +93,11 @@ async function hasGreatPowers(origin) { }); } -function hasOmnipotence() { +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: [ '' ], }); @@ -137,7 +108,7 @@ async function onPermissionsRemoved() { const modified = await syncWithBrowserPermissions(); if ( modified === false ) { return false; } const afterMode = await getDefaultFilteringMode(); - if ( beforeMode > 1 && afterMode <= 1 ) { + if ( beforeMode > MODE_BASIC && afterMode <= MODE_BASIC ) { updateDynamicRules(); } registerInjectables(); @@ -146,6 +117,36 @@ async function onPermissionsRemoved() { /******************************************************************************/ +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 windows.create({ + type: 'popup', + url: pageURL.href, + }); + } + + return browser.tabs.create({ + active: true, + url: pageURL.href, + }); +} + +/******************************************************************************/ + function onMessage(request, sender, callback) { // Does not require trusted origin. @@ -185,7 +186,9 @@ function onMessage(request, sender, callback) { }).then(( ) => { registerInjectables(); callback(); - broadcastMessage({ enabledRulesets: rulesetConfig.enabledRulesets }); + return dnr.getEnabledRulesets(); + }).then(enabledRulesets => { + broadcastMessage({ enabledRulesets }); }); return true; } @@ -196,25 +199,34 @@ function onMessage(request, sender, callback) { getTrustedSites(), getRulesetDetails(), dnr.getEnabledRulesets(), + getAdminRulesets(), + adminReadEx('disabledFeatures'), ]).then(results => { const [ defaultFilteringMode, trustedSites, rulesetDetails, enabledRulesets, + adminRulesets, + disabledFeatures, ] = results; callback({ defaultFilteringMode, trustedSites: Array.from(trustedSites), enabledRulesets, + adminRulesets, maxNumberOfEnabledRulesets: dnr.MAX_NUMBER_OF_ENABLED_STATIC_RULESETS, rulesetDetails: Array.from(rulesetDetails.values()), autoReload: rulesetConfig.autoReload, showBlockedCount: rulesetConfig.showBlockedCount, canShowBlockedCount, - firstRun, + strictBlockMode: rulesetConfig.strictBlockMode, + firstRun: process.firstRun, + isSideloaded, + developerMode: rulesetConfig.developerMode, + disabledFeatures, }); - firstRun = false; + process.firstRun = false; }); return true; } @@ -240,12 +252,28 @@ function onMessage(request, sender, callback) { }); return true; + case 'setStrictBlockMode': + setStrictBlockMode(request.state).then(( ) => { + callback(); + broadcastMessage({ strictBlockMode: rulesetConfig.strictBlockMode }); + }); + return true; + + case 'setDeveloperMode': + rulesetConfig.developerMode = request.state; + toggleDeveloperMode(rulesetConfig.developerMode); + saveRulesetConfig().then(( ) => { + callback(); + }); + return true; + case 'popupPanelData': { Promise.all([ getFilteringMode(request.hostname), hasOmnipotence(), hasGreatPowers(request.origin), getEnabledRulesetsDetails(), + adminReadEx('disabledFeatures'), ]).then(results => { callback({ level: results[0], @@ -253,6 +281,9 @@ function onMessage(request, sender, callback) { hasOmnipotence: results[1], hasGreatPowers: results[2], rulesetDetails: results[3], + isSideloaded, + developerMode: rulesetConfig.developerMode, + disabledFeatures: results[4], }); }); return true; @@ -265,6 +296,10 @@ function onMessage(request, sender, callback) { return true; } + case 'gotoURL': + gotoURL(request.url, request.type); + break; + case 'setFilteringMode': { getFilteringMode(request.hostname).then(actualLevel => { if ( request.level === actualLevel ) { return actualLevel; } @@ -276,6 +311,13 @@ function onMessage(request, sender, callback) { return true; } + case 'getDefaultFilteringMode': { + getDefaultFilteringMode().then(level => { + callback(level); + }); + return true; + } + case 'setDefaultFilteringMode': { getDefaultFilteringMode().then(beforeLevel => setDefaultFilteringMode(request.level).then(afterLevel => @@ -308,9 +350,31 @@ function onMessage(request, sender, callback) { }); return true; + case 'excludeFromStrictBlock': { + excludeFromStrictBlock(request.hostname, request.permanent).then(( ) => { + callback(); + }); + return true; + } + + case 'getMatchedRules': + getMatchedRules(request.tabId).then(entries => { + callback(entries); + }); + return true; + + case 'showMatchedRules': + windows.create({ + type: 'popup', + url: `/matched-rules.html?tab=${request.tabId}`, + }); + break; + default: break; } + + return false; } /******************************************************************************/ @@ -318,20 +382,24 @@ function onMessage(request, sender, callback) { async function start() { await loadRulesetConfig(); - if ( wakeupRun === false ) { - await enableRulesets(rulesetConfig.enabledRulesets); + const currentVersion = getCurrentVersion(); + const isNewVersion = currentVersion !== rulesetConfig.version; + + // The default rulesets may have changed, find out new ruleset to enable, + // obsolete ruleset to remove. + if ( isNewVersion ) { + ubolLog(`Version change: ${rulesetConfig.version} => ${currentVersion}`); + rulesetConfig.version = currentVersion; + await patchDefaultRulesets(); + saveRulesetConfig(); } + const rulesetsUpdated = process.wakeupRun === false && + await enableRulesets(rulesetConfig.enabledRulesets); + // We need to update the regex rules only when ruleset version changes. - if ( wakeupRun === false ) { - const currentVersion = getCurrentVersion(); - if ( currentVersion !== rulesetConfig.version ) { - ubolLog(`Version change: ${rulesetConfig.version} => ${currentVersion}`); - updateDynamicRules().then(( ) => { - rulesetConfig.version = currentVersion; - saveRulesetConfig(); - }); - } + if ( isNewVersion && rulesetsUpdated === false ) { + updateDynamicRules(); } // Permissions may have been removed while the extension was disabled @@ -340,7 +408,7 @@ async function start() { // 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 ( wakeupRun === false || permissionsChanged ) { + if ( process.wakeupRun === false || permissionsChanged ) { registerInjectables(); const enabledRulesets = await dnr.getEnabledRulesets(); @@ -353,7 +421,7 @@ async function start() { // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/declarativeNetRequest // Firefox API does not support `dnr.setExtensionActionOptions` - if ( wakeupRun === false && canShowBlockedCount ) { + if ( process.wakeupRun === false && canShowBlockedCount ) { dnr.setExtensionActionOptions({ displayActionCountAsBadgeText: rulesetConfig.showBlockedCount, }); @@ -365,16 +433,49 @@ async function start() { ( ) => { onPermissionsRemoved(); } ); - if ( firstRun ) { - const disableFirstRunPage = await adminRead('disableFirstRunPage'); - if ( disableFirstRunPage !== true ) { - runtime.openOptionsPage(); + if ( process.firstRun ) { + const enableOptimal = await hasOmnipotence(); + if ( enableOptimal ) { + const afterLevel = await setDefaultFilteringMode(MODE_OPTIMAL); + if ( afterLevel === MODE_OPTIMAL ) { + updateDynamicRules(); + 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 the up to date property is available when needed + if ( process.wakeupRun === false ) { + adminReadEx('disabledFeatures'); + } } -try { - start(); -} catch(reason) { +// https://github.com/uBlockOrigin/uBOL-home/issues/199 +// Force a restart of the extension once when an "internal error" occurs +start().then(( ) => { + localRemove('goodStart'); + return false; +}).catch(reason => { console.trace(reason); -} + if ( process.wakeupRun ) { return; } + return localRead('goodStart').then(goodStart => { + if ( goodStart === false ) { + localRemove('goodStart'); + return false; + } + return localWrite('goodStart', false).then(( ) => true); + }); +}).then(restart => { + if ( restart !== true ) { return; } + runtime.reload(); +}); diff --git a/platform/mv3/extension/js/config.js b/platform/mv3/extension/js/config.js new file mode 100644 index 0000000000000..0c79dd62b18f0 --- /dev/null +++ b/platform/mv3/extension/js/config.js @@ -0,0 +1,76 @@ +/******************************************************************************* + + 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, localWrite, + sessionRead, sessionWrite, +} from './ext.js'; + +/******************************************************************************/ + +export const rulesetConfig = { + version: '', + enabledRulesets: [], + autoReload: true, + showBlockedCount: true, + strictBlockMode: true, + developerMode: false, +}; + +export const process = { + firstRun: false, + wakeupRun: false, +}; + +/******************************************************************************/ + +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; + 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; + sessionWrite('rulesetConfig', rulesetConfig); + return; + } + sessionWrite('rulesetConfig', rulesetConfig); + localWrite('rulesetConfig', rulesetConfig); + process.firstRun = true; +} + +export async function saveRulesetConfig() { + sessionWrite('rulesetConfig', rulesetConfig); + return localWrite('rulesetConfig', rulesetConfig); +} diff --git a/platform/mv3/extension/js/dashboard.js b/platform/mv3/extension/js/dashboard.js index 363f30173fa16..b8c240d5c3c43 100644 --- a/platform/mv3/extension/js/dashboard.js +++ b/platform/mv3/extension/js/dashboard.js @@ -19,10 +19,8 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -import { runtime } from './ext.js'; import { dom } from './dom.js'; +import { runtime } from './ext.js'; /******************************************************************************/ diff --git a/platform/mv3/extension/js/debug.js b/platform/mv3/extension/js/debug.js new file mode 100644 index 0000000000000..0a6ecaffe70ee --- /dev/null +++ b/platform/mv3/extension/js/debug.js @@ -0,0 +1,128 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant 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 { dnr } from './ext.js'; + +/******************************************************************************/ + +export const isSideloaded = dnr.onRuleMatchedDebug instanceof Object; + +/******************************************************************************/ + +export const ubolLog = (...args) => { + // Do not pollute dev console in stable releases. + if ( isSideloaded !== true ) { return; } + console.info('[uBOL]', ...args); +}; + +/******************************************************************************/ + +const rulesets = new Map(); +const bufferSize = isSideloaded ? 256 : 1; +const matchedRules = new Array(bufferSize); +matchedRules.fill(null); +let writePtr = 0; + +const pruneLongLists = list => { + if ( list.length <= 21 ) { return list; } + return [ ...list.slice(0, 10), '...', ...list.slice(-10) ]; + +}; + +const getRuleset = async rulesetId => { + if ( rulesets.has(rulesetId) ) { + return rulesets.get(rulesetId); + } + let rules; + if ( rulesetId === dnr.DYNAMIC_RULESET_ID ) { + rules = await dnr.getDynamicRules().catch(( ) => undefined); + } else { + const response = await fetch(`/rulesets/main/${rulesetId}.json`).catch(( ) => undefined); + if ( response === undefined ) { return; } + rules = await response.json().catch(( ) => undefined); + } + if ( Array.isArray(rules) === false ) { return; } + const ruleset = new Map(); + for ( const rule of rules ) { + const condition = rule.condition; + if ( condition ) { + if ( condition.requestDomains ) { + condition.requestDomains = pruneLongLists(condition.requestDomains); + } + if ( condition.initiatorDomains ) { + condition.initiatorDomains = pruneLongLists(condition.initiatorDomains); + } + } + const ruleId = rule.id; + rule.id = `${rulesetId}/${ruleId}`; + ruleset.set(ruleId, rule); + } + rulesets.set(rulesetId, ruleset); + return ruleset; +}; + +const getRuleDetails = async ruleInfo => { + const { rulesetId, ruleId } = ruleInfo.rule; + const ruleset = await getRuleset(rulesetId); + if ( ruleset === undefined ) { return; } + return { request: ruleInfo.request, rule: ruleset.get(ruleId) }; +}; + +/******************************************************************************/ + +export const getMatchedRules = (( ) => { + const noopFn = ( ) => Promise.resolve([]); + if ( isSideloaded !== true ) { return noopFn; } + + 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); + }; +})(); + +/******************************************************************************/ + +const matchedRuleListener = ruleInfo => { + matchedRules[writePtr] = ruleInfo; + writePtr = (writePtr + 1) % bufferSize; +}; + +export const toggleDeveloperMode = state => { + if ( isSideloaded !== true ) { return; } + if ( state ) { + dnr.onRuleMatchedDebug.addListener(matchedRuleListener); + } else { + dnr.onRuleMatchedDebug.removeListener(matchedRuleListener); + } +}; + +/******************************************************************************/ diff --git a/platform/mv3/extension/js/ext.js b/platform/mv3/extension/js/ext.js index 185fa9c92745d..0a5a98f4f59a2 100644 --- a/platform/mv3/extension/js/ext.js +++ b/platform/mv3/extension/js/ext.js @@ -19,12 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - -/******************************************************************************/ - export const browser = self.browser instanceof Object && self.browser instanceof Element === false @@ -34,6 +28,7 @@ export const browser = export const dnr = browser.declarativeNetRequest; export const i18n = browser.i18n; export const runtime = browser.runtime; +export const windows = browser.windows; /******************************************************************************/ @@ -103,11 +98,17 @@ export async function sessionWrite(key, value) { return browser.storage.session.set({ [key]: value }); } +export async function sessionRemove(key) { + if ( browser.storage instanceof Object === false ) { return; } + if ( browser.storage.session instanceof Object === false ) { return; } + return browser.storage.session.remove(key); +} + /******************************************************************************/ export async function adminRead(key) { if ( browser.storage instanceof Object === false ) { return; } - if ( browser.storage.local instanceof Object === false ) { return; } + if ( browser.storage.managed instanceof Object === false ) { return; } try { const bin = await browser.storage.managed.get(key); if ( bin instanceof Object === false ) { return; } diff --git a/platform/mv3/extension/js/filter-lists.js b/platform/mv3/extension/js/filter-lists.js new file mode 100644 index 0000000000000..2356d57ce13d7 --- /dev/null +++ b/platform/mv3/extension/js/filter-lists.js @@ -0,0 +1,448 @@ +/******************************************************************************* + + 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 { i18n, i18n$ } from './i18n.js'; +import { localRead, localWrite, sendMessage } from './ext.js'; + +/******************************************************************************/ + +export const rulesetMap = new Map(); + +let cachedRulesetData = {}; +let hideUnusedSet = new Set([ 'regions' ]); + +/******************************************************************************/ + +function renderNumber(value) { + return value.toLocaleString(); +} + +/******************************************************************************/ + +function renderTotalRuleCounts() { + let rulesetCount = 0; + let filterCount = 0; + let ruleCount = 0; + for ( const liEntry of qsa$('#lists .listEntry[data-role="leaf"][data-rulesetid]') ) { + if ( qs$(liEntry, 'input[type="checkbox"]:checked') === null ) { continue; } + rulesetCount += 1; + const stats = rulesetStats(liEntry.dataset.rulesetid); + if ( stats === undefined ) { continue; } + ruleCount += stats.ruleCount; + filterCount += stats.filterCount; + } + dom.text('#listsOfBlockedHostsPrompt', i18n$('perRulesetStats') + .replace('{{ruleCount}}', renderNumber(ruleCount)) + .replace('{{filterCount}}', renderNumber(filterCount)) + ); + + dom.cl.toggle(dom.body, 'noMoreRuleset', + rulesetCount === cachedRulesetData.maxNumberOfEnabledRulesets + ); +} + +/******************************************************************************/ + +function updateNodes(listEntries) { + listEntries = listEntries || qs$('#lists'); + const sublistSelector = '.listEntry[data-rulesetid] > .detailbar input'; + const checkedSublistSelector = `${sublistSelector}:checked`; + const adminSublistSelector = '.listEntry.fromAdmin[data-rulesetid] > .detailbar input'; + for ( const listEntry of qsa$(listEntries, '.listEntry[data-nodeid]') ) { + const countElem = qs$(listEntry, ':scope > .detailbar .count'); + if ( countElem === null ) { continue; } + const totalCount = qsa$(listEntry, sublistSelector).length; + const checkedCount = qsa$(listEntry, checkedSublistSelector).length; + dom.text(countElem, `${checkedCount}/${totalCount}`); + const checkboxElem = qs$(listEntry, ':scope > .detailbar .checkbox'); + if ( checkboxElem === null ) { continue; } + const checkboxInput = qs$(checkboxElem, 'input'); + dom.prop(checkboxInput, 'checked', checkedCount !== 0); + dom.cl.toggle(checkboxElem, 'partial', + checkedCount !== 0 && checkedCount !== totalCount + ); + const adminCount = qsa$(listEntry, adminSublistSelector).length; + const fromAdmin = adminCount === totalCount; + dom.cl.toggle(listEntry, 'fromAdmin', fromAdmin); + dom.attr(checkboxInput, 'disabled', fromAdmin ? '' : null); + } +} + +/******************************************************************************/ + +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 filterCount = filters.accepted; + return { ruleCount, filterCount }; +} + +/******************************************************************************/ + +function isAdminRuleset(listkey) { + const { adminRulesets = [] } = cachedRulesetData; + for ( const id of adminRulesets ) { + const pos = id.indexOf(listkey); + if ( pos === 0 ) { return true; } + if ( pos !== 1 ) { continue; } + const c = id.charAt(0); + if ( c === '+' || c === '-' ) { return true; } + } + return false; +} + +/******************************************************************************/ + +export function renderFilterLists(rulesetData) { + cachedRulesetData = rulesetData; + const { enabledRulesets, rulesetDetails } = cachedRulesetData; + + const shouldUpdate = rulesetMap.size !== 0; + + rulesetDetails.forEach(rule => rulesetMap.set(rule.id, rule)); + + const listStatsTemplate = i18n$('perRulesetStats'); + + const initializeListEntry = (ruleset, listEntry) => { + const on = enabledRulesets.includes(ruleset.id); + if ( dom.cl.has(listEntry, 'toggled') === false ) { + dom.prop(qs$(listEntry, ':scope > .detailbar input'), 'checked', on); + } + if ( ruleset.homeURL ) { + dom.attr(qs$(listEntry, 'a.support'), 'href', ruleset.homeURL); + } + dom.cl.toggle(listEntry, 'isDefault', ruleset.id === 'default'); + const stats = rulesetStats(ruleset.id); + if ( stats === undefined ) { return; } + listEntry.title = listStatsTemplate + .replace('{{ruleCount}}', renderNumber(stats.ruleCount)) + .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 + ); + }; + + // Update already rendered DOM lists + if ( shouldUpdate ) { + for ( const listEntry of qsa$('#lists .listEntry[data-rulesetid]') ) { + const rulesetid = listEntry.dataset.rulesetid; + const ruleset = rulesetMap.get(rulesetid); + initializeListEntry(ruleset, listEntry); + } + updateNodes(); + renderTotalRuleCounts(); + return; + } + + const createListEntry = (listDetails, depth) => { + if ( listDetails.lists === undefined ) { + return dom.clone('#templates .listEntry[data-role="leaf"]'); + } + if ( depth !== 0 ) { + return dom.clone('#templates .listEntry[data-role="node"]'); + } + return dom.clone('#templates .listEntry[data-role="rootnode"]'); + }; + + const createListEntries = (parentkey, listTree, depth = 0) => { + const listEntries = dom.clone('#templates .listEntries'); + const treeEntries = Object.entries(listTree); + if ( depth !== 0 ) { + const reEmojis = /\p{Emoji}+/gu; + treeEntries.sort((a ,b) => { + const ap = a[1].preferred === true; + const bp = b[1].preferred === true; + if ( ap !== bp ) { return ap ? -1 : 1; } + const as = (a[1].title || a[0]).replace(reEmojis, ''); + const bs = (b[1].title || b[0]).replace(reEmojis, ''); + return as.localeCompare(bs); + }); + } + for ( const [ listkey, listDetails ] of treeEntries ) { + const listEntry = createListEntry(listDetails, depth); + if ( listDetails.lists === undefined ) { + listEntry.dataset.rulesetid = listkey; + } else { + listEntry.dataset.nodeid = listkey; + dom.cl.toggle(listEntry, 'hideUnused', hideUnusedSet.has(listkey)); + } + qs$(listEntry, ':scope > .detailbar .listname').append( + i18n.patchUnicodeFlags(listDetails.name) + ); + if ( listDetails.lists !== undefined ) { + listEntry.append(createListEntries(listkey, listDetails.lists, depth+1)); + dom.cl.toggle(listEntry, 'expanded', true/*listIsExpanded(listkey)*/); + //updateListNode(listEntry); + } else { + initializeListEntry(listDetails, listEntry); + } + listEntries.append(listEntry); + } + return listEntries; + }; + + // Visually split the filter lists in groups + const groups = new Map([ + [ + 'default', + rulesetDetails.filter(ruleset => + ruleset.id === 'default' + ), + ], [ + 'malware', + rulesetDetails.filter(ruleset => + ruleset.group === 'malware' + ), + ], [ + 'annoyances', + rulesetDetails.filter(ruleset => + ruleset.group === 'annoyances' + ), + ], [ + 'misc', + rulesetDetails.filter(ruleset => + ruleset.id !== 'default' && + ruleset.group === undefined && + typeof ruleset.lang !== 'string' + ), + ], [ + 'regions', + rulesetDetails.filter(ruleset => + ruleset.group === 'regions' + ), + ], + ]); + + dom.cl.toggle(dom.body, 'hideUnused', mustHideUnusedLists('*')); + + // Build list tree + const listTree = {}; + const groupNames = new Map(); + for ( const [ nodeid, rulesets ] of groups ) { + let name = groupNames.get(nodeid); + if ( name === undefined ) { + name = i18n$(`3pGroup${nodeid.charAt(0).toUpperCase()}${nodeid.slice(1)}`); + groupNames.set(nodeid, name); + } + const details = { name, lists: {} }; + listTree[nodeid] = details; + for ( const ruleset of rulesets ) { + if ( ruleset.parent !== undefined ) { + let lists = details.lists; + for ( const parent of ruleset.parent.split('|') ) { + if ( lists[parent] === undefined ) { + lists[parent] = { name: parent, lists: {} }; + } + lists = lists[parent].lists; + } + lists[ruleset.id] = ruleset; + } else { + details.lists[ruleset.id] = ruleset; + } + } + } + // Replace composite list with only one sublist with sublist itself + const promoteLonelySublist = (parent, depth = 0) => { + if ( Boolean(parent.lists) === false ) { return parent; } + const childKeys = Object.keys(parent.lists); + for ( const childKey of childKeys ) { + const child = promoteLonelySublist(parent.lists[childKey], depth + 1); + if ( child === parent.lists[childKey] ) { continue; } + parent.lists[child.id] = child; + delete parent.lists[childKey]; + } + if ( depth === 0 ) { return parent; } + if ( childKeys.length > 1 ) { return parent; } + return parent.lists[childKeys[0]] + }; + for ( const key of Object.keys(listTree) ) { + promoteLonelySublist(listTree[key]); + } + const listEntries = createListEntries('root', listTree); + + updateNodes(listEntries); + + dom.clear('#lists'); + qs$('#lists').append(listEntries); + + renderTotalRuleCounts(); +} + +/******************************************************************************/ + +// Collapsing of unused lists. + +function mustHideUnusedLists(which) { + const hideAll = hideUnusedSet.has('*'); + if ( which === '*' ) { return hideAll; } + return hideUnusedSet.has(which) !== hideAll; +} + +function toggleHideUnusedLists(which) { + const doesHideAll = hideUnusedSet.has('*'); + if ( which === '*' ) { + const mustHide = doesHideAll === false; + hideUnusedSet.clear(); + if ( mustHide ) { + hideUnusedSet.add(which); + } + dom.cl.toggle('#lists', 'hideUnused', mustHide); + dom.cl.toggle('.listEntry[data-nodeid]', 'hideUnused', mustHide); + } else { + const doesHide = hideUnusedSet.has(which); + if ( doesHide ) { + hideUnusedSet.delete(which); + } else { + hideUnusedSet.add(which); + } + const mustHide = doesHide === doesHideAll; + const groupSelector = `.listEntry[data-nodeid="${which}"]`; + dom.cl.toggle(groupSelector, 'hideUnused', mustHide); + } + + localWrite('hideUnusedFilterLists', Array.from(hideUnusedSet)); +} + +dom.on('#lists', 'click', '.listEntry[data-nodeid] > .detailbar, .listExpander', ev => { + toggleHideUnusedLists( + dom.attr(ev.target.closest('[data-nodeid]'), 'data-nodeid') + ); +}); + +// Initialize from saved state. +localRead('hideUnusedFilterLists').then(value => { + if ( Array.isArray(value) === false ) { return; } + hideUnusedSet = new Set(value); + for ( const listEntry of qsa$('[data-nodeid]') ) { + dom.cl.toggle(listEntry, 'hideUnused', + hideUnusedSet.has(listEntry.dataset.nodeid) + ); + } +}); + +/******************************************************************************/ + +const searchFilterLists = ( ) => { + const pattern = dom.prop('#findInLists', 'value') || ''; + dom.cl.toggle('#lists', 'searchMode', pattern !== ''); + if ( pattern === '' ) { return; } + const re = new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i'); + for ( const listEntry of qsa$('#lists [data-role="leaf"]') ) { + if ( dom.cl.has(listEntry, 'fromAdmin') ) { continue; } + const rulesetid = listEntry.dataset.rulesetid; + const rulesetDetails = rulesetMap.get(rulesetid); + if ( rulesetDetails === undefined ) { continue; } + let haystack = perListHaystack.get(rulesetDetails); + if ( haystack === undefined ) { + haystack = [ + rulesetDetails.name, + listEntry.dataset.nodeid, + rulesetDetails.group || '', + rulesetDetails.tags || '', + ].join(' ').trim(); + perListHaystack.set(rulesetDetails, haystack); + } + dom.cl.toggle(listEntry, 'searchMatch', re.test(haystack)); + } + for ( const listEntry of qsa$('#lists .listEntry:not([data-role="leaf"])') ) { + dom.cl.toggle(listEntry, 'searchMatch', + qs$(listEntry, '.listEntries .listEntry.searchMatch') !== null + ); + } +}; + +const perListHaystack = new WeakMap(); + +dom.on('#findInLists', 'input', searchFilterLists); + +/******************************************************************************/ + +const applyEnabledRulesets = (( ) => { + const apply = async ( ) => { + const enabledRulesets = []; + for ( const liEntry of qsa$('#lists .listEntry[data-role="leaf"][data-rulesetid]') ) { + const checked = qs$(liEntry, 'input[type="checkbox"]:checked') !== null; + if ( checked === false ) { continue; } + const { rulesetid } = liEntry.dataset; + if ( dom.cl.has(liEntry, 'fromAdmin') ) { continue; } + enabledRulesets.push(rulesetid); + } + + dom.cl.remove('#lists .listEntry.toggled', 'toggled'); + + if ( enabledRulesets.length === 0 ) { return; } + + await sendMessage({ + what: 'applyRulesets', + enabledRulesets, + }); + }; + + let timer; + + self.addEventListener('beforeunload', ( ) => { + if ( timer !== undefined ) { return; } + self.clearTimeout(timer); + timer = undefined; + apply(); + }); + + return function() { + if ( timer !== undefined ) { + self.clearTimeout(timer); + } + timer = self.setTimeout(( ) => { + timer = undefined; + apply(); + }, 997); + } +})(); + +dom.on('#lists', 'change', '.listEntry input[type="checkbox"]', ev => { + const input = ev.target; + const listEntry = input.closest('.listEntry'); + if ( listEntry === null ) { return; } + if ( listEntry.dataset.nodeid !== undefined ) { + const checkAll = input.checked || + dom.cl.has(qs$(listEntry, ':scope > .detailbar .checkbox'), 'partial'); + for ( const subListEntry of qsa$(listEntry, ':scope > .listEntries .listEntry[data-rulesetid]') ) { + dom.cl.add(subListEntry, 'toggled'); + dom.prop(qsa$(subListEntry, ':scope > .detailbar input'), 'checked', checkAll); + } + } else { + dom.cl.add(listEntry, 'toggled'); + } + updateNodes(); + renderTotalRuleCounts(); + applyEnabledRulesets(); +}); diff --git a/platform/mv3/extension/js/matched-rules.js b/platform/mv3/extension/js/matched-rules.js new file mode 100644 index 0000000000000..75a17caf4f7c6 --- /dev/null +++ b/platform/mv3/extension/js/matched-rules.js @@ -0,0 +1,48 @@ +/******************************************************************************* + + 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$ } from './dom.js'; +import { sendMessage } from './ext.js'; + +/******************************************************************************/ + +const url = new URL(document.location.href); +const tabId = parseInt(url.searchParams.get('tab'), 10) || 0; + +const entries = await sendMessage({ + what: 'getMatchedRules', + tabId, +}); + +const fragment = new DocumentFragment(); +const template = qs$('#matchInfo'); +for ( const entry of (entries || []) ) { + if ( entry instanceof Object === false ) { continue; } + const row = template.content.cloneNode(true); + qs$(row, '.requestInfo').textContent = JSON.stringify(entry.request, null, 2); + qs$(row, '.ruleInfo').textContent = JSON.stringify(entry.rule, null, 2); + fragment.append(row); +} + +dom.empty('#matchedEntries'); +qs$('#matchedEntries').append(fragment); + +/******************************************************************************/ diff --git a/platform/mv3/extension/js/mode-manager.js b/platform/mv3/extension/js/mode-manager.js index e75dbeef58339..a8af4bbb930fe 100644 --- a/platform/mv3/extension/js/mode-manager.js +++ b/platform/mv3/extension/js/mode-manager.js @@ -19,20 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - -/******************************************************************************/ - -import { - browser, - dnr, - localRead, localWrite, localRemove, - sessionRead, sessionWrite, - adminRead, -} from './ext.js'; - import { broadcastMessage, hostnamesFromMatches, @@ -41,9 +27,13 @@ import { } from './utils.js'; import { - TRUSTED_DIRECTIVE_BASE_RULE_ID, - getDynamicRules -} from './ruleset-manager.js'; + browser, + localRead, localWrite, + sessionRead, sessionWrite, +} from './ext.js'; + +import { adminReadEx } from './admin.js'; +import { filteringModesToDNR } from './ruleset-manager.js'; /******************************************************************************/ @@ -79,18 +69,6 @@ const pruneHostnameFromSet = (hostname, hnSet) => { /******************************************************************************/ -const eqSets = (setBefore, setAfter) => { - for ( const hn of setAfter ) { - if ( setBefore.has(hn) === false ) { return false; } - } - for ( const hn of setBefore ) { - if ( setAfter.has(hn) === false ) { return false; } - } - return true; -}; - -/******************************************************************************/ - const serializeModeDetails = details => { return { none: Array.from(details.none), @@ -229,38 +207,40 @@ function applyFilteringMode(filteringModes, hostname, afterLevel) { /******************************************************************************/ -async function readFilteringModeDetails() { - if ( readFilteringModeDetails.cache ) { - return readFilteringModeDetails.cache; - } - const sessionModes = await sessionRead('filteringModeDetails'); - if ( sessionModes instanceof Object ) { - readFilteringModeDetails.cache = unserializeModeDetails(sessionModes); - return readFilteringModeDetails.cache; +export async function readFilteringModeDetails(bypassCache = false) { + if ( bypassCache === false ) { + if ( readFilteringModeDetails.cache ) { + return readFilteringModeDetails.cache; + } + const sessionModes = await sessionRead('filteringModeDetails'); + if ( sessionModes instanceof Object ) { + readFilteringModeDetails.cache = unserializeModeDetails(sessionModes); + return readFilteringModeDetails.cache; + } } let [ userModes, adminNoFiltering ] = await Promise.all([ localRead('filteringModeDetails'), - localRead('adminNoFiltering'), + adminReadEx('noFiltering'), ]); if ( userModes === undefined ) { userModes = { basic: [ 'all-urls' ] }; } userModes = unserializeModeDetails(userModes); if ( Array.isArray(adminNoFiltering) ) { + if ( adminNoFiltering.includes('-*') ) { + userModes.none.clear(); + } for ( const hn of adminNoFiltering ) { - applyFilteringMode(userModes, hn, 0); + if ( hn.charAt(0) === '-' ) { + userModes.none.delete(hn.slice(1)); + } else { + applyFilteringMode(userModes, hn, 0); + } } } filteringModesToDNR(userModes); sessionWrite('filteringModeDetails', serializeModeDetails(userModes)); readFilteringModeDetails.cache = userModes; - adminRead('noFiltering').then(results => { - if ( results ) { - localWrite('adminNoFiltering', results); - } else { - localRemove('adminNoFiltering'); - } - }); return userModes; } @@ -272,10 +252,11 @@ async function writeFilteringModeDetails(afterDetails) { localWrite('filteringModeDetails', data); sessionWrite('filteringModeDetails', data); readFilteringModeDetails.cache = unserializeModeDetails(data); - - Promise.all([ + return Promise.all([ getDefaultFilteringMode(), getTrustedSites(), + localWrite('filteringModeDetails', data), + sessionWrite('filteringModeDetails', data), ]).then(results => { broadcastMessage({ defaultFilteringMode: results[0], @@ -286,68 +267,6 @@ async function writeFilteringModeDetails(afterDetails) { /******************************************************************************/ -async function filteringModesToDNR(modes) { - const dynamicRuleMap = await getDynamicRules(); - const presentRule = dynamicRuleMap.get(TRUSTED_DIRECTIVE_BASE_RULE_ID+0); - const presentNone = new Set( - presentRule && presentRule.condition.requestDomains - ); - if ( eqSets(presentNone, modes.none) ) { return; } - const removeRuleIds = []; - if ( presentRule !== undefined ) { - removeRuleIds.push(TRUSTED_DIRECTIVE_BASE_RULE_ID+0); - removeRuleIds.push(TRUSTED_DIRECTIVE_BASE_RULE_ID+1); - dynamicRuleMap.delete(TRUSTED_DIRECTIVE_BASE_RULE_ID+0); - dynamicRuleMap.delete(TRUSTED_DIRECTIVE_BASE_RULE_ID+1); - } - const addRules = []; - const noneHostnames = [ ...modes.none ]; - const notNoneHostnames = [ ...modes.basic, ...modes.optimal, ...modes.complete ]; - if ( noneHostnames.length !== 0 ) { - const rule0 = { - id: TRUSTED_DIRECTIVE_BASE_RULE_ID+0, - action: { type: 'allowAllRequests' }, - condition: { - resourceTypes: [ 'main_frame' ], - }, - priority: 100, - }; - if ( modes.none.has('all-urls') === false ) { - rule0.condition.requestDomains = noneHostnames.slice(); - } else if ( notNoneHostnames.length !== 0 ) { - rule0.condition.excludedRequestDomains = notNoneHostnames.slice(); - } - addRules.push(rule0); - dynamicRuleMap.set(TRUSTED_DIRECTIVE_BASE_RULE_ID+0, rule0); - // https://github.com/uBlockOrigin/uBOL-home/issues/114 - const rule1 = { - id: TRUSTED_DIRECTIVE_BASE_RULE_ID+1, - action: { type: 'allow' }, - condition: { - resourceTypes: [ 'script' ], - }, - priority: 100, - }; - if ( modes.none.has('all-urls') === false ) { - rule1.condition.initiatorDomains = noneHostnames.slice(); - } else if ( notNoneHostnames.length !== 0 ) { - rule1.condition.excludedInitiatorDomains = notNoneHostnames.slice(); - } - addRules.push(rule1); - dynamicRuleMap.set(TRUSTED_DIRECTIVE_BASE_RULE_ID+1, rule1); - } - const updateOptions = {}; - if ( addRules.length ) { - updateOptions.addRules = addRules; - } - if ( removeRuleIds.length ) { - updateOptions.removeRuleIds = removeRuleIds; - } - await dnr.updateDynamicRules(updateOptions); -} - -/******************************************************************************/ - export async function getFilteringModeDetails() { const actualDetails = await readFilteringModeDetails(); return { @@ -394,6 +313,11 @@ export async function setTrustedSites(hostnames) { 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); diff --git a/platform/mv3/extension/js/popup.js b/platform/mv3/extension/js/popup.js index 29b993b24aa39..98b4d54ce1434 100644 --- a/platform/mv3/extension/js/popup.js +++ b/platform/mv3/extension/js/popup.js @@ -19,17 +19,11 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - -/******************************************************************************/ - import { browser, + localRead, localWrite, runtime, sendMessage, - localRead, localWrite, } from './ext.js'; import { dom, qs$ } from './dom.js'; @@ -40,7 +34,7 @@ import punycode from './punycode.js'; const popupPanelData = {}; const currentTab = {}; -let tabHostname = ''; +const tabURL = new URL(runtime.getURL('/')); /******************************************************************************/ @@ -50,6 +44,14 @@ function normalizedHostname(hn) { /******************************************************************************/ +function renderAdminRules() { + const { disabledFeatures: forbid = [] } = popupPanelData; + if ( forbid.length === 0 ) { return; } + dom.body.dataset.forbid = forbid.join(' '); +} + +/******************************************************************************/ + const BLOCKING_MODE_MAX = 3; function setFilteringMode(level, commit = false) { @@ -66,8 +68,8 @@ function setFilteringMode(level, commit = false) { } async function commitFilteringMode() { - if ( tabHostname === '' ) { return; } - const targetHostname = normalizedHostname(tabHostname); + if ( tabURL.hostname === '' ) { return; } + const targetHostname = normalizedHostname(tabURL.hostname); const modeSlider = qs$('.filteringModeSlider'); const afterLevel = parseInt(modeSlider.dataset.level, 10); const beforeLevel = parseInt(modeSlider.dataset.levelBefore, 10); @@ -97,7 +99,11 @@ async function commitFilteringMode() { setFilteringMode(actualLevel); } if ( actualLevel !== beforeLevel && popupPanelData.autoReload ) { - browser.tabs.reload(currentTab.id); + self.setTimeout(( ) => { + browser.tabs.update(currentTab.id, { + url: tabURL.href, + }); + }, 437); } } @@ -265,6 +271,36 @@ dom.on('#lessButton', 'click', ( ) => { /******************************************************************************/ +dom.on('#showMatchedRules', 'click', ev => { + if ( ev.isTrusted !== true ) { return; } + if ( ev.button !== 0 ) { return; } + sendMessage({ + what: 'showMatchedRules', + tabId: currentTab.id, + }); +}); + +/******************************************************************************/ + +dom.on('[data-i18n-title="popupTipReport"]', 'click', ev => { + if ( ev.isTrusted !== true ) { return; } + let url; + try { + url = new URL(currentTab.url); + } catch(_) { + } + if ( url === undefined ) { return; } + const reportURL = new URL(runtime.getURL('/report.html')); + reportURL.searchParams.set('url', url.href); + reportURL.searchParams.set('mode', popupPanelData.level); + sendMessage({ + what: 'gotoURL', + url: `${reportURL.pathname}${reportURL.search}`, + }); +}); + +/******************************************************************************/ + dom.on('[data-i18n-title="popupTipDashboard"]', 'click', ev => { if ( ev.isTrusted !== true ) { return; } if ( ev.button !== 0 ) { return; } @@ -283,8 +319,12 @@ async function init() { let url; try { + const strictBlockURL = runtime.getURL('/strictblock.'); url = new URL(currentTab.url); - tabHostname = url.hostname || ''; + if ( url.href.startsWith(strictBlockURL) ) { + url = new URL(url.hash.slice(1)); + } + tabURL.href = url.href || ''; } catch(ex) { } @@ -292,16 +332,29 @@ async function init() { const response = await sendMessage({ what: 'popupPanelData', origin: url.origin, - hostname: normalizedHostname(tabHostname), + hostname: normalizedHostname(tabURL.hostname), }); if ( response instanceof Object ) { Object.assign(popupPanelData, response); } } + renderAdminRules(); + setFilteringMode(popupPanelData.level); - dom.text('#hostname', punycode.toUnicode(tabHostname)); + dom.text('#hostname', punycode.toUnicode(tabURL.hostname)); + + dom.cl.toggle('#showMatchedRules', '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 || [] ) { diff --git a/platform/mv3/extension/js/report.js b/platform/mv3/extension/js/report.js new file mode 100644 index 0000000000000..35c3a85094100 --- /dev/null +++ b/platform/mv3/extension/js/report.js @@ -0,0 +1,154 @@ +/******************************************************************************* + + 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 { dnr, runtime } from './ext.js'; +import { dom, qs$ } from './dom.js'; +import { sendMessage } from './ext.js'; + +/******************************************************************************/ + +const reportedPage = (( ) => { + const url = new URL(window.location.href); + try { + const pageURL = url.searchParams.get('url'); + if ( pageURL === null ) { return null; } + const parsedURL = new URL(pageURL); + parsedURL.username = ''; + parsedURL.password = ''; + parsedURL.hash = ''; + const select = qs$('select[name="url"]'); + dom.text(select.options[0], parsedURL.href); + if ( parsedURL.search !== '' ) { + const option = dom.create('option'); + parsedURL.search = ''; + dom.text(option, parsedURL.href); + select.append(option); + } + if ( parsedURL.pathname !== '/' ) { + const option = dom.create('option'); + parsedURL.pathname = ''; + dom.text(option, parsedURL.href); + select.append(option); + } + return { + hostname: parsedURL.hostname.replace(/^(m|mobile|www)\./, ''), + mode: url.searchParams.get('mode'), + }; + } catch(ex) { + } + return null; +})(); + +/******************************************************************************/ + +function reportSpecificFilterType() { + return qs$('select[name="type"]').value; +} + +/******************************************************************************/ + +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' + ); + const issueType = reportSpecificFilterType(); + let title = `${reportedPage.hostname}: ${issueType}`; + if ( qs$('#isNSFW').checked ) { + title = `[nsfw] ${title}`; + } + githubURL.searchParams.set('title', title); + githubURL.searchParams.set( + 'url_address_of_the_web_page', + '`' + qs$('select[name="url"]').value + '`' + ); + 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), + '```', + '', + ].join('\n'); + githubURL.searchParams.set('configuration', configBody); + sendMessage({ what: 'gotoURL', url: githubURL.href }); +} + +/******************************************************************************/ + +(async ( ) => { + dom.on('[data-url]', 'click', ev => { + const elem = ev.target.closest('[data-url]'); + const url = dom.attr(elem, 'data-url'); + if ( typeof url !== 'string' || url === '' ) { return; } + sendMessage({ what: 'gotoURL', url }); + ev.preventDefault(); + }); + + if ( reportedPage !== null ) { + dom.on('[data-i18n="supportReportSpecificButton"]', 'click', ev => { + reportSpecificFilterIssue(); + ev.preventDefault(); + }); + + dom.on('[data-i18n="supportFindSpecificButton"]', 'click', ev => { + const url = new URL('https://github.com/uBlockOrigin/uAssets/issues'); + url.searchParams.set('q', `is:issue sort:updated-desc "${reportedPage.hostname}" in:title`); + sendMessage({ what: 'gotoURL', url: url.href }); + ev.preventDefault(); + }); + } + +})(); diff --git a/platform/mv3/extension/js/ruleset-manager.js b/platform/mv3/extension/js/ruleset-manager.js index a484e1d21d17d..4e3ab50b2e382 100644 --- a/platform/mv3/extension/js/ruleset-manager.js +++ b/platform/mv3/extension/js/ruleset-manager.js @@ -19,29 +19,45 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ +import { + browser, + dnr, + i18n, + localRead, localRemove, localWrite, + runtime, + sessionRead, sessionRemove, sessionWrite, +} from './ext.js'; -'use strict'; +import { + rulesetConfig, + saveRulesetConfig, +} from './config.js'; -/******************************************************************************/ -import { browser, dnr, i18n } from './ext.js'; import { fetchJSON } from './fetch.js'; -import { ubolLog } from './utils.js'; +import { getAdminRulesets } from './admin.js'; +import { ubolLog } from './debug.js'; /******************************************************************************/ -const RULE_REALM_SIZE = 1000000; -const REGEXES_REALM_START = 1000000; -const REGEXES_REALM_END = REGEXES_REALM_START + RULE_REALM_SIZE; -const REMOVEPARAMS_REALM_START = REGEXES_REALM_END; -const REMOVEPARAMS_REALM_END = REMOVEPARAMS_REALM_START + RULE_REALM_SIZE; -const REDIRECT_REALM_START = REMOVEPARAMS_REALM_END; -const REDIRECT_REALM_END = REDIRECT_REALM_START + RULE_REALM_SIZE; -const MODIFYHEADERS_REALM_START = REDIRECT_REALM_END; -const MODIFYHEADERS_REALM_END = MODIFYHEADERS_REALM_START + RULE_REALM_SIZE; +const STRICTBLOCK_BASE_RULE_ID = 7000000; const TRUSTED_DIRECTIVE_BASE_RULE_ID = 8000000; +let dynamicRuleId = 1; + +/******************************************************************************/ + +const eqSets = (setBefore, setAfter) => { + if ( setBefore.size !== setAfter.size ) { return false; } + for ( const hn of setAfter ) { + if ( setBefore.has(hn) === false ) { return false; } + } + for ( const hn of setBefore ) { + if ( setAfter.has(hn) === false ) { return false; } + } + return true; +}; + /******************************************************************************/ function getRulesetDetails() { @@ -59,73 +75,50 @@ function getRulesetDetails() { /******************************************************************************/ -function getDynamicRules() { - if ( getDynamicRules.dynamicRuleMapPromise !== undefined ) { - return getDynamicRules.dynamicRuleMapPromise; - } - getDynamicRules.dynamicRuleMapPromise = dnr.getDynamicRules().then(rules => { - const rulesMap = new Map(rules.map(rule => [ rule.id, rule ])); - ubolLog(`Dynamic rule count: ${rulesMap.size}`); - ubolLog(`Available dynamic rule count: ${dnr.MAX_NUMBER_OF_DYNAMIC_AND_SESSION_RULES - rulesMap.size}`); - return rulesMap; - }); - return getDynamicRules.dynamicRuleMapPromise; -} - -/******************************************************************************/ - async function pruneInvalidRegexRules(realm, rulesIn) { - // Avoid testing already tested regexes - const dynamicRules = await dnr.getDynamicRules(); - const validRegexSet = new Set( - dynamicRules.filter(rule => - rule.condition?.regexFilter && true || false - ).map(rule => - rule.condition.regexFilter - ) - ); + const rejectedRegexRules = []; + + 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}`); + return false; + }); + }; // Validate regex-based rules const toCheck = []; - const rejectedRegexRules = []; for ( const rule of rulesIn ) { if ( rule.condition?.regexFilter === undefined ) { toCheck.push(true); continue; } - const { - regexFilter: regex, - isUrlFilterCaseSensitive: isCaseSensitive - } = rule.condition; - if ( validRegexSet.has(regex) ) { - toCheck.push(true); + const { regexFilter } = rule.condition; + if ( pruneInvalidRegexRules.validated.has(regexFilter) ) { + toCheck.push(pruneInvalidRegexRules.validated.get(regexFilter)); continue; } - toCheck.push( - dnr.isRegexSupported({ regex, isCaseSensitive }).then(result => { - if ( result.isSupported ) { return true; } - rejectedRegexRules.push(`\t${regex} ${result.reason}`); - return false; - }) - ); + toCheck.push(validateRegex(regexFilter)); } // Collate results const isValid = await Promise.all(toCheck); if ( rejectedRegexRules.length !== 0 ) { - ubolLog( - `${realm} realm: rejected regexes:\n`, + ubolLog(`${realm} realm: rejected regexes:\n`, rejectedRegexRules.join('\n') ); } return rulesIn.filter((v, i) => isValid[i]); } +pruneInvalidRegexRules.validated = new Map(); /******************************************************************************/ -async function updateRegexRules() { +async function updateRegexRules(toAdd) { const rulesetDetails = await getEnabledRulesetsDetails(); // Fetch regexes for all enabled rulesets @@ -138,69 +131,31 @@ async function updateRegexRules() { // Collate all regexes rules const allRules = []; - let regexRuleId = REGEXES_REALM_START; for ( const rules of regexRulesets ) { if ( Array.isArray(rules) === false ) { continue; } for ( const rule of rules ) { - rule.id = regexRuleId++; + rule.id = dynamicRuleId++; allRules.push(rule); } } + if ( allRules.length === 0 ) { return; } - const validatedRules = await pruneInvalidRegexRules('regexes', allRules); - - // Add validated regex rules to dynamic ruleset without affecting rules - // outside regex rules realm. - const dynamicRuleMap = await getDynamicRules(); - const newRuleMap = new Map(validatedRules.map(rule => [ rule.id, rule ])); - const addRules = []; - const removeRuleIds = []; + const validRules = await pruneInvalidRegexRules('regexes', allRules); + if ( validRules.length === 0 ) { return; } - for ( const oldRule of dynamicRuleMap.values() ) { - if ( oldRule.id < REGEXES_REALM_START ) { continue; } - if ( oldRule.id >= REGEXES_REALM_END ) { continue; } - const newRule = newRuleMap.get(oldRule.id); - if ( newRule === undefined ) { - removeRuleIds.push(oldRule.id); - dynamicRuleMap.delete(oldRule.id); - } else if ( JSON.stringify(oldRule) !== JSON.stringify(newRule) ) { - removeRuleIds.push(oldRule.id); - addRules.push(newRule); - dynamicRuleMap.set(oldRule.id, newRule); - } - } - - for ( const newRule of newRuleMap.values() ) { - if ( dynamicRuleMap.has(newRule.id) ) { continue; } - addRules.push(newRule); - dynamicRuleMap.set(newRule.id, newRule); - } - - if ( addRules.length === 0 && removeRuleIds.length === 0 ) { return; } - - if ( removeRuleIds.length !== 0 ) { - ubolLog(`Remove ${removeRuleIds.length} DNR regex rules`); - } - if ( addRules.length !== 0 ) { - ubolLog(`Add ${addRules.length} DNR regex rules`); - } - - return dnr.updateDynamicRules({ addRules, removeRuleIds }).catch(reason => { - console.error(`updateRegexRules() / ${reason}`); - }); + ubolLog(`Add ${validRules.length} DNR regex rules`); + toAdd.push(...validRules); } /******************************************************************************/ -async function updateRemoveparamRules() { +async function updateRemoveparamRules(toAdd) { const [ hasOmnipotence, rulesetDetails, - dynamicRuleMap, ] = await Promise.all([ browser.permissions.contains({ origins: [ '' ] }), getEnabledRulesetsDetails(), - getDynamicRules(), ]); // Fetch removeparam rules for all enabled rulesets @@ -214,69 +169,32 @@ async function updateRemoveparamRules() { // Removeparam rules can only be enforced with omnipotence const allRules = []; if ( hasOmnipotence ) { - let removeparamRuleId = REMOVEPARAMS_REALM_START; for ( const rules of removeparamRulesets ) { if ( Array.isArray(rules) === false ) { continue; } for ( const rule of rules ) { - rule.id = removeparamRuleId++; + rule.id = dynamicRuleId++; allRules.push(rule); } } } + if ( allRules.length === 0 ) { return; } - const validatedRules = await pruneInvalidRegexRules('removeparam', allRules); + const validRules = await pruneInvalidRegexRules('removeparam', allRules); + if ( validRules.length === 0 ) { return; } - // Add removeparam rules to dynamic ruleset without affecting rules - // outside removeparam rules realm. - const newRuleMap = new Map(validatedRules.map(rule => [ rule.id, rule ])); - const addRules = []; - const removeRuleIds = []; - - for ( const oldRule of dynamicRuleMap.values() ) { - if ( oldRule.id < REMOVEPARAMS_REALM_START ) { continue; } - if ( oldRule.id >= REMOVEPARAMS_REALM_END ) { continue; } - const newRule = newRuleMap.get(oldRule.id); - if ( newRule === undefined ) { - removeRuleIds.push(oldRule.id); - dynamicRuleMap.delete(oldRule.id); - } else if ( JSON.stringify(oldRule) !== JSON.stringify(newRule) ) { - removeRuleIds.push(oldRule.id); - addRules.push(newRule); - dynamicRuleMap.set(oldRule.id, newRule); - } - } - - for ( const newRule of newRuleMap.values() ) { - if ( dynamicRuleMap.has(newRule.id) ) { continue; } - addRules.push(newRule); - dynamicRuleMap.set(newRule.id, newRule); - } - - if ( addRules.length === 0 && removeRuleIds.length === 0 ) { return; } - - if ( removeRuleIds.length !== 0 ) { - ubolLog(`Remove ${removeRuleIds.length} DNR removeparam rules`); - } - if ( addRules.length !== 0 ) { - ubolLog(`Add ${addRules.length} DNR removeparam rules`); - } - - return dnr.updateDynamicRules({ addRules, removeRuleIds }).catch(reason => { - console.error(`updateRemoveparamRules() / ${reason}`); - }); + ubolLog(`Add ${validRules.length} DNR removeparam rules`); + toAdd.push(...validRules); } /******************************************************************************/ -async function updateRedirectRules() { +async function updateRedirectRules(toAdd) { const [ hasOmnipotence, rulesetDetails, - dynamicRuleMap, ] = await Promise.all([ browser.permissions.contains({ origins: [ '' ] }), getEnabledRulesetsDetails(), - getDynamicRules(), ]); // Fetch redirect rules for all enabled rulesets @@ -290,69 +208,32 @@ async function updateRedirectRules() { // Redirect rules can only be enforced with omnipotence const allRules = []; if ( hasOmnipotence ) { - let redirectRuleId = REDIRECT_REALM_START; for ( const rules of redirectRulesets ) { if ( Array.isArray(rules) === false ) { continue; } for ( const rule of rules ) { - rule.id = redirectRuleId++; + rule.id = dynamicRuleId++; allRules.push(rule); } } } + if ( allRules.length === 0 ) { return; } - const validatedRules = await pruneInvalidRegexRules('redirect', allRules); + const validRules = await pruneInvalidRegexRules('redirect', allRules); + if ( validRules.length === 0 ) { return; } - // Add redirect rules to dynamic ruleset without affecting rules - // outside redirect rules realm. - const newRuleMap = new Map(validatedRules.map(rule => [ rule.id, rule ])); - const addRules = []; - const removeRuleIds = []; - - for ( const oldRule of dynamicRuleMap.values() ) { - if ( oldRule.id < REDIRECT_REALM_START ) { continue; } - if ( oldRule.id >= REDIRECT_REALM_END ) { continue; } - const newRule = newRuleMap.get(oldRule.id); - if ( newRule === undefined ) { - removeRuleIds.push(oldRule.id); - dynamicRuleMap.delete(oldRule.id); - } else if ( JSON.stringify(oldRule) !== JSON.stringify(newRule) ) { - removeRuleIds.push(oldRule.id); - addRules.push(newRule); - dynamicRuleMap.set(oldRule.id, newRule); - } - } - - for ( const newRule of newRuleMap.values() ) { - if ( dynamicRuleMap.has(newRule.id) ) { continue; } - addRules.push(newRule); - dynamicRuleMap.set(newRule.id, newRule); - } - - if ( addRules.length === 0 && removeRuleIds.length === 0 ) { return; } - - if ( removeRuleIds.length !== 0 ) { - ubolLog(`Remove ${removeRuleIds.length} DNR redirect rules`); - } - if ( addRules.length !== 0 ) { - ubolLog(`Add ${addRules.length} DNR redirect rules`); - } - - return dnr.updateDynamicRules({ addRules, removeRuleIds }).catch(reason => { - console.error(`updateRedirectRules() / ${reason}`); - }); + ubolLog(`Add ${validRules.length} DNR redirect rules`); + toAdd.push(...validRules); } /******************************************************************************/ -async function updateModifyHeadersRules() { +async function updateModifyHeadersRules(toAdd) { const [ hasOmnipotence, rulesetDetails, - dynamicRuleMap, ] = await Promise.all([ browser.permissions.contains({ origins: [ '' ] }), getEnabledRulesetsDetails(), - getDynamicRules(), ]); // Fetch modifyHeaders rules for all enabled rulesets @@ -366,76 +247,317 @@ async function updateModifyHeadersRules() { // Redirect rules can only be enforced with omnipotence const allRules = []; if ( hasOmnipotence ) { - let ruleId = MODIFYHEADERS_REALM_START; for ( const rules of rulesets ) { if ( Array.isArray(rules) === false ) { continue; } for ( const rule of rules ) { - rule.id = ruleId++; + rule.id = dynamicRuleId++; allRules.push(rule); } } } + if ( allRules.length === 0 ) { return; } - const validatedRules = await pruneInvalidRegexRules('modify-headers', allRules); + const validRules = await pruneInvalidRegexRules('modify-headers', allRules); + if ( validRules.length === 0 ) { return; } - // Add modifyHeaders rules to dynamic ruleset without affecting rules - // outside modifyHeaders realm. - const newRuleMap = new Map(validatedRules.map(rule => [ rule.id, rule ])); - const addRules = []; - const removeRuleIds = []; + ubolLog(`Add ${validRules.length} DNR modify-headers rules`); + toAdd.push(...validRules); +} - for ( const oldRule of dynamicRuleMap.values() ) { - if ( oldRule.id < MODIFYHEADERS_REALM_START ) { continue; } - if ( oldRule.id >= MODIFYHEADERS_REALM_END ) { continue; } - const newRule = newRuleMap.get(oldRule.id); - if ( newRule === undefined ) { - removeRuleIds.push(oldRule.id); - dynamicRuleMap.delete(oldRule.id); - } else if ( JSON.stringify(oldRule) !== JSON.stringify(newRule) ) { - removeRuleIds.push(oldRule.id); - addRules.push(newRule); - dynamicRuleMap.set(oldRule.id, newRule); - } - } +/******************************************************************************/ + +async function updateStrictBlockRules(dynamicRules, sessionRules) { + if ( rulesetConfig.strictBlockMode === false ) { return; } + + const [ + hasOmnipotence, + rulesetDetails, + permanentlyExcluded = [], + temporarilyExcluded = [], + ] = await Promise.all([ + browser.permissions.contains({ origins: [ '' ] }), + getEnabledRulesetsDetails(), + localRead('excludedStrictBlockHostnames'), + sessionRead('excludedStrictBlockHostnames'), + ]); - for ( const newRule of newRuleMap.values() ) { - if ( dynamicRuleMap.has(newRule.id) ) { continue; } - addRules.push(newRule); - dynamicRuleMap.set(newRule.id, newRule); + // Fetch strick-block hostnames + const toFetch = []; + for ( const details of rulesetDetails ) { + if ( details.rules.strictblock === 0 ) { continue; } + toFetch.push(fetchJSON(`/rulesets/strictblock/${details.id}`)); } + const strictblockRulesets = await Promise.all(toFetch); - if ( addRules.length === 0 && removeRuleIds.length === 0 ) { return; } + // Strict-block rules can only be enforced with omnipotence + let toStrictBlock = new Set(); + if ( hasOmnipotence ) { + for ( const hostnames of strictblockRulesets ) { + if ( Array.isArray(hostnames) === false ) { continue; } + toStrictBlock = toStrictBlock.union(new Set(hostnames)); + } + } else { + if ( permanentlyExcluded.length !== 0 ) { + localRemove('excludedStrictBlockHostnames'); + permanentlyExcluded.length = 0; + } + if ( temporarilyExcluded.length !== 0 ) { + sessionRemove('excludedStrictBlockHostnames'); + temporarilyExcluded.length = 0; + } + } + for ( const hn of permanentlyExcluded ) { + toStrictBlock.delete(hn); + } + if ( toStrictBlock.size === 0 ) { return; } + const manifest = runtime.getManifest(); + let strictblockPath = ''; + for ( const war of manifest.web_accessible_resources ) { + if ( war.resources.length !== 1 ) { continue; } + if ( war.resources[0].startsWith('/strictblock.') === false ) { continue; } + strictblockPath = runtime.getURL(war.resources[0]); + break; + } + if ( strictblockPath === '' ) { return; } + const dynamicRule = { + id: STRICTBLOCK_BASE_RULE_ID, + action: { + type: 'redirect', + redirect: { + regexSubstitution: `${strictblockPath}#\\0`, + }, + }, + condition: { + regexFilter: '^https?://.+', + requestDomains: Array.from(toStrictBlock), + resourceTypes: [ 'main_frame' ], + }, + priority: 29, + }; + if ( permanentlyExcluded.length !== 0 ) { + dynamicRule.condition.excludedRequestDomains = permanentlyExcluded; + } + dynamicRules.push(dynamicRule); + ubolLog(`Add 1 DNR dynamic rule with ${toStrictBlock.size} strictblock domains`); + + if ( temporarilyExcluded.length === 0 ) { return; } + sessionRules.push({ + id: STRICTBLOCK_BASE_RULE_ID, + action: { + type: 'allow', + }, + condition: { + requestDomains: temporarilyExcluded, + resourceTypes: [ 'main_frame' ], + }, + priority: 29, + }); + ubolLog(`Add 1 DNR session rule with ${temporarilyExcluded.length} excluded strictblock domains`); +} - if ( removeRuleIds.length !== 0 ) { - ubolLog(`Remove ${removeRuleIds.length} DNR modifyHeaders rules`); +async function commitStrictBlockRules() { + const [ + beforePermanentRules, + beforeTemporaryRules, + ] = await Promise.all([ + dnr.getDynamicRules({ ruleIds: [ STRICTBLOCK_BASE_RULE_ID ] }), + dnr.getSessionRules({ ruleIds: [ STRICTBLOCK_BASE_RULE_ID ] }), + ]); + if ( beforePermanentRules?.length ) { + ubolLog(`Remove 1 DNR dynamic strictblock rule`); } - if ( addRules.length !== 0 ) { - ubolLog(`Add ${addRules.length} DNR modifyHeaders rules`); + if ( beforeTemporaryRules?.length ) { + ubolLog(`Remove 1 DNR session strictblock rule`); } + const afterPermanentRules = []; + const afterTemporaryRules = []; + await updateStrictBlockRules(afterPermanentRules, afterTemporaryRules) + return Promise.all([ + dnr.updateDynamicRules({ + addRules: afterPermanentRules, + removeRuleIds: beforePermanentRules.map(rule => rule.id), + }), + dnr.updateSessionRules({ + addRules: afterTemporaryRules, + removeRuleIds: beforeTemporaryRules.map(rule => rule.id), + }), + ]); +} - return dnr.updateDynamicRules({ addRules, removeRuleIds }).catch(reason => { - console.error(`updateModifyHeadersRules() / ${reason}`); - }); +async function excludeFromStrictBlock(hostname, permanent) { + if ( typeof hostname !== 'string' || hostname === '' ) { return; } + const readFn = permanent ? localRead : sessionRead; + const hostnames = new Set(await readFn('excludedStrictBlockHostnames')); + hostnames.add(hostname); + const writeFn = permanent ? localWrite : sessionWrite; + await writeFn('excludedStrictBlockHostnames', Array.from(hostnames)); + return commitStrictBlockRules(); } -/******************************************************************************/ +async function setStrictBlockMode(state) { + const newState = Boolean(state); + if ( newState === rulesetConfig.strictBlockMode ) { return; } + rulesetConfig.strictBlockMode = newState; + const promises = [ saveRulesetConfig() ]; + if ( newState === false ) { + promises.push( + localRemove('excludedStrictBlockHostnames'), + sessionRemove('excludedStrictBlockHostnames') + ); + } + await Promise.all(promises); + return commitStrictBlockRules(); +} -// TODO: group all omnipotence-related rules into one realm. +/******************************************************************************/ async function updateDynamicRules() { - return Promise.all([ - updateRegexRules(), - updateRemoveparamRules(), - updateRedirectRules(), - updateModifyHeadersRules(), + dynamicRuleId = 1; + const dynamicRules = []; + const sessionRules = []; + const [ + dynamicRuleIds, + sessionRuleIds, + ] = await Promise.all([ + dnr.getDynamicRules().then(rules => + rules.map(rule => rule.id) + .filter(id => id < TRUSTED_DIRECTIVE_BASE_RULE_ID) + ), + dnr.getSessionRules().then(rules => rules.map(rule => rule.id)), + updateRegexRules(dynamicRules), + updateRemoveparamRules(dynamicRules), + updateRedirectRules(dynamicRules), + updateModifyHeadersRules(dynamicRules), + updateStrictBlockRules(dynamicRules, sessionRules), ]); + if ( dynamicRules.length === 0 && dynamicRuleIds.length === 0 ) { return; } + const promises = []; + if ( dynamicRules.length !== 0 || dynamicRuleIds.length !== 0 ) { + promises.push( + dnr.updateDynamicRules({ + addRules: dynamicRules, + removeRuleIds: dynamicRuleIds, + }).then(( ) => { + if ( dynamicRuleIds.length !== 0 ) { + ubolLog(`Remove ${dynamicRuleIds.length} dynamic DNR rules`); + } + if ( dynamicRules.length !== 0 ) { + ubolLog(`Add ${dynamicRules.length} dynamic DNR rules`); + } + }).catch(reason => { + console.error(`updateDynamicRules() / ${reason}`); + }) + ); + } + if ( sessionRules.length !== 0 || sessionRuleIds.length !== 0 ) { + promises.push( + dnr.updateSessionRules({ + addRules: sessionRules, + removeRuleIds: sessionRuleIds, + }).then(( ) => { + if ( sessionRuleIds.length !== 0 ) { + ubolLog(`Remove ${sessionRuleIds.length} session DNR rules`); + } + if ( sessionRules.length !== 0 ) { + ubolLog(`Add ${sessionRules.length} session DNR rules`); + } + }).catch(reason => { + console.error(`updateSessionRules() / ${reason}`); + }) + ); + } + return Promise.all(promises); } /******************************************************************************/ -async function defaultRulesetsFromLanguage() { - const out = [ 'default' ]; +async function filteringModesToDNR(modes) { + const trustedRules = await dnr.getDynamicRules({ + ruleIds: [ TRUSTED_DIRECTIVE_BASE_RULE_ID+0 ], + }); + const trustedRule = trustedRules.length !== 0 && trustedRules[0] || undefined; + const beforeRequestDomainSet = new Set(trustedRule?.condition.requestDomains); + const beforeExcludedRrequestDomainSet = new Set(trustedRule?.condition.excludedRequestDomains); + if ( trustedRule !== undefined && beforeRequestDomainSet.size === 0 ) { + beforeRequestDomainSet.add('all-urls'); + } else { + beforeExcludedRrequestDomainSet.add('all-urls'); + } + + 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; + } else { + afterRequestDomainSet = noneHostnames; + afterExcludedRequestDomainSet = new Set([ 'all-urls' ]); + } + + if ( eqSets(beforeRequestDomainSet, afterRequestDomainSet) ) { + if ( eqSets(beforeExcludedRrequestDomainSet, afterExcludedRequestDomainSet) ) { + return; + } + } + + const removeRuleIds = []; + if ( trustedRule ) { + removeRuleIds.push( + TRUSTED_DIRECTIVE_BASE_RULE_ID+0, + TRUSTED_DIRECTIVE_BASE_RULE_ID+1 + ); + } + + const allowEverywhere = afterRequestDomainSet.delete('all-urls'); + afterExcludedRequestDomainSet.delete('all-urls'); + + const addRules = []; + 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); + } else if ( afterExcludedRequestDomainSet.size !== 0 ) { + rule0.condition.excludedRequestDomains = Array.from(afterExcludedRequestDomainSet); + } + addRules.push(rule0); + // https://github.com/uBlockOrigin/uBOL-home/issues/114 + const rule1 = { + id: TRUSTED_DIRECTIVE_BASE_RULE_ID+1, + action: { type: 'allow' }, + condition: { + resourceTypes: [ 'script' ], + }, + 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(); + } + addRules.push(rule1); + } + + if ( addRules.length === 0 && removeRuleIds.length === 0 ) { return; } + + return dnr.updateDynamicRules({ addRules, removeRuleIds }); +} +/******************************************************************************/ + +async function defaultRulesetsFromLanguage() { const dropCountry = lang => { const pos = lang.indexOf('-'); if ( pos === -1 ) { return lang; } @@ -453,8 +575,17 @@ async function defaultRulesetsFromLanguage() { `\\b(${Array.from(langSet).join('|')})\\b` ); + const manifest = runtime.getManifest(); + const rulesets = manifest.declarative_net_request.rule_resources; const rulesetDetails = await getRulesetDetails(); - for ( const [ id, details ] of rulesetDetails ) { + const out = []; + for ( const ruleset of rulesets ) { + 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); @@ -464,9 +595,63 @@ async function defaultRulesetsFromLanguage() { /******************************************************************************/ +async function patchDefaultRulesets() { + const [ + oldDefaultIds = [], + newDefaultIds, + ] = await Promise.all([ + localRead('defaultRulesetIds'), + defaultRulesetsFromLanguage(), + ]); + + 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 ) { + if ( oldDefaultIds.includes(id) ) { continue; } + toAdd.push(id); + } + for ( const id of oldDefaultIds ) { + if ( newDefaultIds.includes(id) ) { continue; } + toRemove.push(id); + } + for ( const id of rulesetConfig.enabledRulesets ) { + if ( validIds.has(id) ) { continue; } + toRemove.push(id); + } + localWrite('defaultRulesetIds', newDefaultIds); + if ( toAdd.length === 0 && toRemove.length === 0 ) { return; } + const enabledRulesets = new Set(rulesetConfig.enabledRulesets); + toAdd.forEach(id => enabledRulesets.add(id)); + toRemove.forEach(id => enabledRulesets.delete(id)); + const patchedRulesets = Array.from(enabledRulesets); + ubolLog(`Patched rulesets: ${rulesetConfig.enabledRulesets} => ${patchedRulesets}`); + rulesetConfig.enabledRulesets = patchedRulesets; +} + +/******************************************************************************/ + async function enableRulesets(ids) { const afterIds = new Set(ids); - const beforeIds = new Set(await dnr.getEnabledRulesets()); + const [ beforeIds, adminIds, rulesetDetails ] = await Promise.all([ + dnr.getEnabledRulesets().then(ids => new Set(ids)), + getAdminRulesets(), + getRulesetDetails(), + ]); + + for ( const token of adminIds ) { + const c0 = token.charAt(0); + const id = token.slice(1); + if ( c0 === '+' ) { + afterIds.add(id); + } else if ( c0 === '-' ) { + afterIds.delete(id); + } + } + const enableRulesetSet = new Set(); const disableRulesetSet = new Set(); for ( const id of afterIds ) { @@ -478,13 +663,8 @@ async function enableRulesets(ids) { disableRulesetSet.add(id); } - if ( enableRulesetSet.size === 0 && disableRulesetSet.size === 0 ) { - return; - } - // Be sure the rulesets to enable/disable do exist in the current version, // otherwise the API throws. - const rulesetDetails = await getRulesetDetails(); for ( const id of enableRulesetSet ) { if ( rulesetDetails.has(id) ) { continue; } enableRulesetSet.delete(id); @@ -493,6 +673,11 @@ async function enableRulesets(ids) { if ( rulesetDetails.has(id) ) { continue; } disableRulesetSet.delete(id); } + + if ( enableRulesetSet.size === 0 && disableRulesetSet.size === 0 ) { + return false; + } + const enableRulesetIds = Array.from(enableRulesetSet); const disableRulesetIds = Array.from(disableRulesetSet); @@ -503,8 +688,10 @@ async function enableRulesets(ids) { ubolLog(`Disable ruleset: ${disableRulesetIds}`); } await dnr.updateEnabledRulesets({ enableRulesetIds, disableRulesetIds }); - - return updateDynamicRules(); + + await updateDynamicRules(); + + return true; } /******************************************************************************/ @@ -529,11 +716,13 @@ async function getEnabledRulesetsDetails() { /******************************************************************************/ export { - TRUSTED_DIRECTIVE_BASE_RULE_ID, - getRulesetDetails, - getDynamicRules, - enableRulesets, defaultRulesetsFromLanguage, + enableRulesets, + excludeFromStrictBlock, + filteringModesToDNR, + getRulesetDetails, getEnabledRulesetsDetails, + patchDefaultRulesets, + setStrictBlockMode, updateDynamicRules, }; diff --git a/platform/mv3/extension/js/scripting-manager.js b/platform/mv3/extension/js/scripting-manager.js index e6eebf29f7b9b..23a6444ea0acd 100644 --- a/platform/mv3/extension/js/scripting-manager.js +++ b/platform/mv3/extension/js/scripting-manager.js @@ -19,18 +19,13 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - -/******************************************************************************/ +import * as ut from './utils.js'; import { browser } from './ext.js'; import { fetchJSON } from './fetch.js'; -import { getFilteringModeDetails } from './mode-manager.js'; import { getEnabledRulesetsDetails } from './ruleset-manager.js'; - -import * as ut from './utils.js'; +import { getFilteringModeDetails } from './mode-manager.js'; +import { ubolLog } from './debug.js'; /******************************************************************************/ @@ -276,7 +271,7 @@ function registerProcedural(context) { allFrames: true, matches, excludeMatches, - runAt: 'document_end', + runAt: 'document_start', }; // register @@ -455,8 +450,8 @@ function registerScriptlet(context, scriptletDetails) { targetHostnames = permissionGrantedHostnames; } else { targetHostnames = ut.intersectHostnameIters( - permissionGrantedHostnames, - scriptletHostnames + scriptletHostnames, + permissionGrantedHostnames ); } } @@ -478,6 +473,7 @@ function registerScriptlet(context, scriptletDetails) { // `MAIN` world not yet supported in Firefox if ( isGecko === false ) { directive.world = 'MAIN'; + directive.matchOriginAsFallback = true; } // register @@ -542,13 +538,13 @@ async function registerInjectables(origins) { toRemove.push(...Array.from(before.keys())); if ( toRemove.length !== 0 ) { - ut.ubolLog(`Unregistered ${toRemove} content (css/js)`); + ubolLog(`Unregistered ${toRemove} content (css/js)`); await browser.scripting.unregisterContentScripts({ ids: toRemove }) .catch(reason => { console.info(reason); }); } if ( toAdd.length !== 0 ) { - ut.ubolLog(`Registered ${toAdd.map(v => v.id)} content (css/js)`); + ubolLog(`Registered ${toAdd.map(v => v.id)} content (css/js)`); await browser.scripting.registerContentScripts(toAdd) .catch(reason => { console.info(reason); }); } diff --git a/platform/mv3/extension/js/scripting/css-procedural.js b/platform/mv3/extension/js/scripting/css-procedural.js index 7f50f80989d32..58fd4d6d7efe6 100644 --- a/platform/mv3/extension/js/scripting/css-procedural.js +++ b/platform/mv3/extension/js/scripting/css-procedural.js @@ -21,8 +21,6 @@ /* jshint esversion:11 */ -'use strict'; - /******************************************************************************/ // Important! @@ -112,18 +110,21 @@ const uBOL_injectCSS = (css, count = 10) => { }; const nonVisualElements = { + head: true, + link: true, + meta: true, script: true, style: true, }; const regexFromString = (s, exact = false) => { if ( s === '' ) { return /^/; } - const match = /^\/(.+)\/([i]?)$/.exec(s); + 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, 'i'); + return new RegExp(exact ? `^${reStr}$` : reStr); }; /******************************************************************************/ @@ -242,7 +243,7 @@ class PSelectorMatchesMediaTask extends PSelectorTask { if ( this.mql.media === 'not all' ) { return; } this.mql.addEventListener('change', ( ) => { if ( proceduralFilterer instanceof Object === false ) { return; } - proceduralFilterer.onDOMChanged([ null ]); + proceduralFilterer.onDOMChanged(); }); } transpose(node, output) { @@ -269,6 +270,32 @@ class PSelectorMatchesPathTask extends PSelectorTask { /******************************************************************************/ +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(); @@ -295,28 +322,27 @@ class PSelectorOthersTask extends PSelectorTask { 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 ) { + while ( keep !== null && keep !== body && keep !== head ) { toKeep.add(keep); toDiscard.delete(keep); discard = keep.previousElementSibling; while ( discard !== null ) { - if ( - nonVisualElements[discard.localName] !== true && - toKeep.has(discard) === false - ) { - toDiscard.add(discard); + 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 && - toKeep.has(discard) === false - ) { - toDiscard.add(discard); + if ( nonVisualElements[discard.localName] !== true ) { + if ( toKeep.has(discard) === false ) { + toDiscard.add(discard); + } } discard = discard.nextElementSibling; } @@ -461,7 +487,7 @@ class PSelectorWatchAttrs extends PSelectorTask { // TODO: Is it worth trying to re-apply only the current selector? handler() { if ( proceduralFilterer instanceof Object ) { - proceduralFilterer.onDOMChanged([ null ]); + proceduralFilterer.onDOMChanged(); } } transpose(node, output) { @@ -570,6 +596,7 @@ PSelector.prototype.operatorToTaskMap = new Map([ [ 'matches-css-before', PSelectorMatchesCSSBeforeTask ], [ 'matches-media', PSelectorMatchesMediaTask ], [ 'matches-path', PSelectorMatchesPathTask ], + [ 'matches-prop', PSelectorMatchesPropTask ], [ 'min-text-length', PSelectorMinTextLengthTask ], [ 'not', PSelectorIfNotTask ], [ 'others', PSelectorOthersTask ], diff --git a/platform/mv3/extension/js/settings.js b/platform/mv3/extension/js/settings.js index 6f50055df6554..d924d6f59ae70 100644 --- a/platform/mv3/extension/js/settings.js +++ b/platform/mv3/extension/js/settings.js @@ -19,183 +19,29 @@ Home: https://github.com/gorhill/uBlock */ -import { browser, localRead, localWrite, sendMessage } from './ext.js'; -import { dom, qs$, qsa$ } from './dom.js'; -import { i18n, i18n$ } from './i18n.js'; +import { browser, sendMessage } from './ext.js'; +import { dom, qs$ } from './dom.js'; import punycode from './punycode.js'; +import { renderFilterLists } from './filter-lists.js'; /******************************************************************************/ -const rulesetMap = new Map(); let cachedRulesetData = {}; -let hideUnusedSet = new Set([ 'regions' ]); /******************************************************************************/ -function renderNumber(value) { - return value.toLocaleString(); -} - function hashFromIterable(iter) { return Array.from(iter).sort().join('\n'); } /******************************************************************************/ -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 filterCount = filters.accepted; - return { ruleCount, filterCount }; -} - -/******************************************************************************/ - -function renderFilterLists() { - const { enabledRulesets, rulesetDetails } = cachedRulesetData; - const listGroupTemplate = qs$('#templates .groupEntry'); - const listEntryTemplate = qs$('#templates .listEntry'); - const listStatsTemplate = i18n$('perRulesetStats'); - const groupNames = new Map([ [ 'user', '' ] ]); - - const liFromListEntry = function(ruleset, li, hideUnused) { - if ( !li ) { - li = dom.clone(listEntryTemplate); - } - const on = enabledRulesets.includes(ruleset.id); - dom.cl.toggle(li, 'checked', on); - dom.cl.toggle(li, 'unused', hideUnused && !on); - qs$(li, 'input[type="checkbox"]').checked = on; - if ( dom.attr(li, 'data-listkey') !== ruleset.id ) { - dom.attr(li, 'data-listkey', ruleset.id); - qs$(li, '.listname').append(i18n.patchUnicodeFlags(ruleset.name)); - dom.cl.remove(li, 'toRemove'); - if ( ruleset.homeURL ) { - dom.cl.add(li, 'support'); - dom.attr(qs$(li, 'a.support'), 'href', ruleset.homeURL); - } else { - dom.cl.remove(li, 'support'); - } - if ( ruleset.instructionURL ) { - dom.cl.add(li, 'mustread'); - dom.attr(qs$(li, 'a.mustread'), 'href', ruleset.instructionURL); - } else { - dom.cl.remove(li, 'mustread'); - } - dom.cl.toggle(li, 'isDefault', ruleset.id === 'default'); - } - const stats = rulesetStats(ruleset.id); - li.title = listStatsTemplate - .replace('{{ruleCount}}', renderNumber(stats.ruleCount)) - .replace('{{filterCount}}', renderNumber(stats.filterCount)); - dom.attr( - qs$(li, '.input.checkbox'), - 'disabled', - stats.ruleCount === 0 ? '' : null - ); - dom.cl.remove(li, 'discard'); - return li; - }; - - const listEntryCountFromGroup = function(groupRulesets) { - if ( Array.isArray(groupRulesets) === false ) { return ''; } - let count = 0, - total = 0; - for ( const ruleset of groupRulesets ) { - if ( enabledRulesets.includes(ruleset.id) ) { - count += 1; - } - total += 1; - } - return total !== 0 ? - `(${count.toLocaleString()}/${total.toLocaleString()})` : - ''; - }; - - const liFromListGroup = function(groupKey, groupRulesets) { - let liGroup = qs$(`#lists > .groupEntry[data-groupkey="${groupKey}"]`); - if ( liGroup === null ) { - liGroup = dom.clone(listGroupTemplate); - let groupName = groupNames.get(groupKey); - if ( groupName === undefined ) { - groupName = i18n$('3pGroup' + groupKey.charAt(0).toUpperCase() + groupKey.slice(1)); - groupNames.set(groupKey, groupName); - } - if ( groupName !== '' ) { - dom.text(qs$(liGroup, '.geName'), groupName); - } - } - if ( qs$(liGroup, '.geName:empty') === null ) { - dom.text( - qs$(liGroup, '.geCount'), - listEntryCountFromGroup(groupRulesets) - ); - } - const hideUnused = mustHideUnusedLists(groupKey); - dom.cl.toggle(liGroup, 'hideUnused', hideUnused); - const ulGroup = qs$(liGroup, '.listEntries'); - if ( !groupRulesets ) { return liGroup; } - groupRulesets.sort(function(a, b) { - return (a.name || '').localeCompare(b.name || ''); - }); - for ( let i = 0; i < groupRulesets.length; i++ ) { - const liEntry = liFromListEntry( - groupRulesets[i], - ulGroup.children[i], - hideUnused - ); - if ( liEntry.parentElement === null ) { - ulGroup.appendChild(liEntry); - } - } - return liGroup; - }; - - // Visually split the filter lists in groups - const ulLists = qs$('#lists'); - const groups = new Map([ - [ - 'default', - rulesetDetails.filter(ruleset => - ruleset.id === 'default' - ), - ], - [ - 'annoyances', - rulesetDetails.filter(ruleset => - ruleset.group === 'annoyances' - ), - ], - [ - 'misc', - rulesetDetails.filter(ruleset => - ruleset.id !== 'default' && - ruleset.group === undefined && - typeof ruleset.lang !== 'string' - ), - ], - [ - 'regions', - rulesetDetails.filter(ruleset => - typeof ruleset.lang === 'string' - ), - ], - ]); - - dom.cl.toggle(dom.body, 'hideUnused', mustHideUnusedLists('*')); - - for ( const [ groupKey, groupRulesets ] of groups ) { - const liGroup = liFromListGroup(groupKey, groupRulesets); - dom.attr(liGroup, 'data-groupkey', groupKey); - if ( liGroup.parentElement === null ) { - ulLists.appendChild(liGroup); - } +function renderAdminRules() { + const { disabledFeatures: forbid = [] } = cachedRulesetData; + if ( forbid.length === 0 ) { return; } + dom.body.dataset.forbid = forbid.join(' '); + if ( forbid.includes('dashboard') ) { + dom.body.dataset.pane = 'about'; } } @@ -221,26 +67,21 @@ function renderWidgets() { } } - // Compute total counts - let rulesetCount = 0; - let filterCount = 0; - let ruleCount = 0; - for ( const liEntry of qsa$('#lists .listEntry[data-listkey]') ) { - if ( qs$(liEntry, 'input[type="checkbox"]:checked') === null ) { continue; } - rulesetCount += 1; - const stats = rulesetStats(liEntry.dataset.listkey); - if ( stats === undefined ) { continue; } - ruleCount += stats.ruleCount; - filterCount += stats.filterCount; + { + const input = qs$('#strictBlockMode input[type="checkbox"]'); + const canStrictBlock = cachedRulesetData.defaultFilteringMode > 1; + 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); + } } - dom.text('#listsOfBlockedHostsPrompt', i18n$('perRulesetStats') - .replace('{{ruleCount}}', ruleCount.toLocaleString()) - .replace('{{filterCount}}', filterCount.toLocaleString()) - ); - - dom.cl.toggle(dom.body, 'noMoreRuleset', - rulesetCount === cachedRulesetData.maxNumberOfEnabledRulesets - ); } /******************************************************************************/ @@ -285,7 +126,7 @@ async function onFilteringModeChange(ev) { default: break; } - renderFilterLists(); + renderFilterLists(cachedRulesetData); renderWidgets(); } @@ -312,11 +153,25 @@ dom.on('#showBlockedCount input[type="checkbox"]', 'change', ev => { }); }); +dom.on('#strictBlockMode input[type="checkbox"]', 'change', ev => { + sendMessage({ + what: 'setStrictBlockMode', + state: ev.target.checked, + }); +}); + +dom.on('#developerMode input[type="checkbox"]', 'change', ev => { + sendMessage({ + what: 'setDeveloperMode', + state: ev.target.checked, + }); +}); + /******************************************************************************/ function renderTrustedSites() { const textarea = qs$('#trustedSites'); - const hostnames = cachedRulesetData.trustedSites; + const hostnames = cachedRulesetData.trustedSites || []; textarea.value = hostnames.map(hn => punycode.toUnicode(hn)).join('\n'); if ( textarea.value !== '' ) { textarea.value += '\n'; @@ -325,7 +180,7 @@ function renderTrustedSites() { function changeTrustedSites() { const hostnames = getStagedTrustedSites(); - const hash = hashFromIterable(cachedRulesetData.trustedSites); + const hash = hashFromIterable(cachedRulesetData.trustedSites || []); if ( hashFromIterable(hostnames) === hash ) { return; } sendMessage({ what: 'setTrustedSites', @@ -352,90 +207,12 @@ self.addEventListener('beforeunload', changeTrustedSites); /******************************************************************************/ -async function applyEnabledRulesets() { - const enabledRulesets = []; - for ( const liEntry of qsa$('#lists .listEntry[data-listkey]') ) { - const checked = qs$(liEntry, 'input[type="checkbox"]:checked') !== null; - dom.cl.toggle(liEntry, 'checked', checked); - if ( checked === false ) { continue; } - enabledRulesets.push(liEntry.dataset.listkey); - } - - await sendMessage({ - what: 'applyRulesets', - enabledRulesets, - }); - - renderWidgets(); -} - -dom.on('#lists', 'change', '.listEntry input[type="checkbox"]', ( ) => { - applyEnabledRulesets(); -}); - -/******************************************************************************/ - -// Collapsing of unused lists. - -function mustHideUnusedLists(which) { - const hideAll = hideUnusedSet.has('*'); - if ( which === '*' ) { return hideAll; } - return hideUnusedSet.has(which) !== hideAll; +function listen() { + const bc = new self.BroadcastChannel('uBOL'); + bc.onmessage = listen.onmessage; } -function toggleHideUnusedLists(which) { - const doesHideAll = hideUnusedSet.has('*'); - let groupSelector; - let mustHide; - if ( which === '*' ) { - mustHide = doesHideAll === false; - groupSelector = ''; - hideUnusedSet.clear(); - if ( mustHide ) { - hideUnusedSet.add(which); - } - dom.cl.toggle(dom.body, 'hideUnused', mustHide); - dom.cl.toggle('.groupEntry[data-groupkey]', 'hideUnused', mustHide); - } else { - const doesHide = hideUnusedSet.has(which); - if ( doesHide ) { - hideUnusedSet.delete(which); - } else { - hideUnusedSet.add(which); - } - mustHide = doesHide === doesHideAll; - groupSelector = `.groupEntry[data-groupkey="${which}"]`; - dom.cl.toggle(groupSelector, 'hideUnused', mustHide); - } - - for ( const elem of qsa$(`#lists ${groupSelector} .listEntry[data-listkey] input[type="checkbox"]:not(:checked)`) ) { - dom.cl.toggle( - elem.closest('.listEntry[data-listkey]'), - 'unused', - mustHide - ); - } - - localWrite('hideUnusedFilterLists', Array.from(hideUnusedSet)); -} - -dom.on('#lists', 'click', '.groupEntry[data-groupkey] > .geDetails', ev => { - toggleHideUnusedLists( - dom.attr(ev.target.closest('[data-groupkey]'), 'data-groupkey') - ); -}); - -// Initialize from saved state. -localRead('hideUnusedFilterLists').then(value => { - if ( Array.isArray(value) === false ) { return; } - hideUnusedSet = new Set(value); -}); - -/******************************************************************************/ - -const bc = new self.BroadcastChannel('uBOL'); - -bc.onmessage = ev => { +listen.onmessage = ev => { const message = ev.data; if ( message instanceof Object === false ) { return; } const local = cachedRulesetData; @@ -477,6 +254,20 @@ bc.onmessage = ev => { } } + if ( message.strictBlockMode !== undefined ) { + if ( message.strictBlockMode !== local.strictBlockMode ) { + local.strictBlockMode = message.strictBlockMode; + render = true; + } + } + + if ( message.adminRulesets !== undefined ) { + if ( hashFromIterable(message.adminRulesets) !== hashFromIterable(local.adminRulesets) ) { + local.adminRulesets = message.adminRulesets; + render = true; + } + } + if ( message.enabledRulesets !== undefined ) { if ( hashFromIterable(message.enabledRulesets) !== hashFromIterable(local.enabledRulesets) ) { local.enabledRulesets = message.enabledRulesets; @@ -485,7 +276,7 @@ bc.onmessage = ev => { } if ( render === false ) { return; } - renderFilterLists(); + renderFilterLists(cachedRulesetData); renderWidgets(); }; @@ -496,13 +287,14 @@ sendMessage({ }).then(data => { if ( !data ) { return; } cachedRulesetData = data; - rulesetMap.clear(); - cachedRulesetData.rulesetDetails.forEach(rule => rulesetMap.set(rule.id, rule)); try { - renderFilterLists(); + renderAdminRules(); + renderFilterLists(cachedRulesetData); renderWidgets(); + dom.cl.remove(dom.body, 'loading'); } catch(ex) { } + listen(); }).catch(reason => { console.trace(reason); }); diff --git a/platform/mv3/extension/js/strictblock.js b/platform/mv3/extension/js/strictblock.js new file mode 100644 index 0000000000000..2e8c74c67e5ea --- /dev/null +++ b/platform/mv3/extension/js/strictblock.js @@ -0,0 +1,267 @@ +/******************************************************************************* + + 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 { dom, qs$ } from './dom.js'; +import { fetchJSON } from './fetch.js'; +import { getEnabledRulesetsDetails } from './ruleset-manager.js'; +import { i18n$ } from './i18n.js'; +import { sendMessage } from './ext.js'; +import { urlSkip } from './urlskip.js'; + +/******************************************************************************/ + +const rulesetDetailsPromise = getEnabledRulesetsDetails(); + +/******************************************************************************/ + +function urlToFragment(raw) { + try { + const fragment = new DocumentFragment(); + const url = new URL(raw); + const hn = url.hostname; + const i = raw.indexOf(hn); + const b = document.createElement('b'); + b.append(hn); + fragment.append(raw.slice(0,i), b, raw.slice(i+hn.length)); + return fragment; + } catch(_) { + } + return raw; +} + +/******************************************************************************/ + +async function proceed() { + await sendMessage({ + what: 'excludeFromStrictBlock', + hostname: toURL.hostname, + permanent: qs$('#disableWarning').checked, + }); + window.location.replace(toURL.href); +} + +/******************************************************************************/ + +const toURL = new URL('about:blank'); + +try { + toURL.href = self.location.hash.slice(1); +} catch(_) { +} + +dom.clear('#theURL > p > span:first-of-type'); +qs$('#theURL > p > span:first-of-type').append(urlToFragment(toURL.href)); + +/******************************************************************************/ + +function fragmentFromTemplate(template, placeholder, text, details) { + const fragment = new DocumentFragment(); + const pos = template.indexOf(placeholder); + if ( pos === -1 ) { + fragment.append(template); + return fragment; + } + const elem = document.createElement(details.tag); + const { attributes } = details; + if ( attributes ) { + for ( let i = 0; i < attributes.length; i+= 2 ) { + elem.setAttribute(attributes[i+0], attributes[i+1]); + } + } + elem.append(text); + fragment.append( + template.slice(0, pos), + elem, + template.slice(pos + placeholder.length) + ); + return fragment; +} + +/******************************************************************************/ + +// https://github.com/gorhill/uBlock/issues/691 +// Parse URL to extract as much useful information as possible. This is +// useful to assist the user in deciding whether to navigate to the web page. +(( ) => { + const reURL = /^https?:\/\//; + + const liFromParam = function(name, value) { + if ( value === '' ) { + value = name; + name = ''; + } + const li = dom.create('li'); + let span = dom.create('span'); + dom.text(span, name); + li.appendChild(span); + if ( name !== '' && value !== '' ) { + li.appendChild(document.createTextNode(' = ')); + } + span = dom.create('span'); + if ( reURL.test(value) ) { + const a = dom.create('a'); + dom.attr(a, 'href', value); + dom.text(a, value); + span.appendChild(a); + } else { + dom.text(span, value); + } + li.appendChild(span); + return li; + }; + + // https://github.com/uBlockOrigin/uBlock-issues/issues/1649 + // Limit recursion. + const renderParams = function(parentNode, rawURL, depth = 0) { + let url; + try { + url = new URL(rawURL); + } catch(ex) { + return false; + } + + const search = url.search.slice(1); + if ( search === '' ) { return false; } + + url.search = ''; + const li = liFromParam(i18n$('strictblockNoParamsPrompt'), url.href); + parentNode.appendChild(li); + + const params = new self.URLSearchParams(search); + for ( const [ name, value ] of params ) { + const li = liFromParam(name, value); + if ( depth < 2 && reURL.test(value) ) { + const ul = dom.create('ul'); + renderParams(ul, value, depth + 1); + li.appendChild(ul); + } + parentNode.appendChild(li); + } + + return true; + }; + + if ( renderParams(qs$('#parsed'), toURL.href) === false ) { return; } + + dom.cl.remove('#toggleParse', 'hidden'); + + dom.on('#toggleParse', 'click', ( ) => { + dom.cl.toggle('#theURL', 'collapsed'); + //vAPI.localStorage.setItem( + // 'document-blocked-expand-url', + // (dom.cl.has('#theURL', 'collapsed') === false).toString() + //); + }); + + //vAPI.localStorage.getItemAsync('document-blocked-expand-url').then(value => { + // dom.cl.toggle('#theURL', 'collapsed', value !== 'true' && value !== true); + //}); +})(); + +/******************************************************************************/ + +// Find which list caused the blocking. +(async ( ) => { + const rulesetDetails = await rulesetDetailsPromise; + let iList = -1; + const searchInList = async i => { + if ( iList !== -1 ) { return; } + const hostnames = new Set( + await fetchJSON(`/rulesets/strictblock/${rulesetDetails[i].id}`) + ); + if ( iList !== -1 ) { return; } + let hn = toURL.hostname; + for (;;) { + if ( hostnames.has(hn) ) { iList = i; break; } + const pos = hn.indexOf('.'); + if ( pos === -1 ) { break; } + hn = hn.slice(pos+1); + } + }; + const toFetch = []; + for ( let i = 0; i < rulesetDetails.length; i++ ) { + if ( rulesetDetails[i].rules.strictblock === 0 ) { continue; } + toFetch.push(searchInList(i)); + } + if ( toFetch.length === 0 ) { return; } + await Promise.all(toFetch); + if ( iList === -1 ) { return; } + const fragment = fragmentFromTemplate( + i18n$('strictblockReasonSentence1'), + '{{listname}}', rulesetDetails[iList].name, + { tag: 'q' } + ); + qs$('#reason').append(fragment); + dom.attr('#reason', 'hidden', null); +})(); + +/******************************************************************************/ + +// Offer to skip redirection whenever possible +(async ( ) => { + const rulesetDetails = await rulesetDetailsPromise; + const toFetch = []; + for ( const details of rulesetDetails ) { + if ( details.rules.urlskip === 0 ) { continue; } + toFetch.push(fetchJSON(`/rulesets/urlskip/${details.id}`)); + } + if ( toFetch.length === 0 ) { return; } + const urlskipLists = await Promise.all(toFetch); + for ( const urlskips of urlskipLists ) { + for ( const urlskip of urlskips ) { + const re = new RegExp(urlskip.re, urlskip.c ? undefined : 'i'); + if ( re.test(toURL.href) === false ) { continue; } + const finalURL = urlSkip(toURL.href, false, urlskip.steps); + if ( finalURL === undefined ) { continue; } + const fragment = fragmentFromTemplate( + i18n$('strictblockRedirectSentence1'), + '{{url}}', urlToFragment(finalURL), + { tag: 'a', attributes: [ 'href', finalURL, 'class', 'code' ] } + ); + qs$('#urlskip').append(fragment); + dom.attr('#urlskip', 'hidden', null); + return; + } + } +})(); + +/******************************************************************************/ + +// https://www.reddit.com/r/uBlockOrigin/comments/breeux/ +if ( window.history.length > 1 ) { + dom.on('#back', 'click', ( ) => { window.history.back(); }); + qs$('#bye').style.display = 'none'; +} else { + dom.on('#bye', 'click', ( ) => { window.close(); }); + qs$('#back').style.display = 'none'; +} + +dom.on('#disableWarning', 'change', ev => { + const checked = ev.target.checked; + dom.cl.toggle('[data-i18n="strictblockBack"]', 'disabled', checked); + dom.cl.toggle('[data-i18n="strictblockClose"]', 'disabled', checked); +}); + +dom.on('#proceed', 'click', ( ) => { proceed(); }); + +dom.cl.remove(dom.body, 'loading'); + +/******************************************************************************/ diff --git a/platform/mv3/extension/js/utils.js b/platform/mv3/extension/js/utils.js index cadeaea0b64c3..7bf6e13503dfd 100644 --- a/platform/mv3/extension/js/utils.js +++ b/platform/mv3/extension/js/utils.js @@ -19,14 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - -/******************************************************************************/ - -import { browser } from './ext.js'; - /******************************************************************************/ function parsedURLromOrigin(origin) { @@ -55,6 +47,13 @@ const isDescendantHostname = (hna, hnb) => { return hna.charCodeAt(hna.length - hnb.length - 1) === 0x2E /* '.' */; }; +/** + * Returns whether a hostname is part of a collection, or is descendant of an + * item in the collection. + * @param hna - the hostname representing the needle. + * @param iterb - an iterable representing the haystack of hostnames. + */ + const isDescendantHostnameOfIter = (hna, iterb) => { const setb = iterb instanceof Set ? iterb : new Set(iterb); if ( setb.has('all-urls') || setb.has('*') ) { return true; } @@ -68,6 +67,13 @@ const isDescendantHostnameOfIter = (hna, iterb) => { return false; }; +/** + * Returns all hostnames in the first collection which are equal or descendant + * of hostnames in the second collection. + * @param itera - an iterable which hostnames must be filtered out. + * @param iterb - an iterable which hostnames must be matched. + */ + const intersectHostnameIters = (itera, iterb) => { const setb = iterb instanceof Set ? iterb : new Set(iterb); if ( setb.has('all-urls') || setb.has('*') ) { return Array.from(itera); } @@ -114,7 +120,7 @@ const hostnamesFromMatches = origins => { out.push('all-urls'); continue; } - const match = /^\*:\/\/(?:\*\.)?([^\/]+)\/\*/.exec(origin); + const match = /^\*:\/\/(?:\*\.)?([^/]+)\/\*/.exec(origin); if ( match === null ) { continue; } out.push(match[1]); } @@ -123,33 +129,15 @@ const hostnamesFromMatches = origins => { /******************************************************************************/ -export const broadcastMessage = message => { +const broadcastMessage = message => { const bc = new self.BroadcastChannel('uBOL'); bc.postMessage(message); }; /******************************************************************************/ -const ubolLog = (...args) => { - // Do not pollute dev console in stable releases. - if ( shouldLog !== true ) { return; } - console.info('[uBOL]', ...args); -}; - -const shouldLog = (( ) => { - const { id } = browser.runtime; - // https://addons.mozilla.org/en-US/firefox/addon/ublock-origin-lite/ - if ( id === 'uBOLite@raymondhill.net' ) { return false; } - // https://chromewebstore.google.com/detail/ddkjiahejlhfcafbddmgiahcphecmpfh - if ( id === 'ddkjiahejlhfcafbddmgiahcphecmpfh' ) { return false; } - // https://microsoftedge.microsoft.com/addons/detail/cimighlppcgcoapaliogpjjdehbnofhn - if ( id === 'cimighlppcgcoapaliogpjjdehbnofhn' ) { return false; } - return true; -})(); - -/******************************************************************************/ - export { + broadcastMessage, parsedURLromOrigin, toBroaderHostname, isDescendantHostname, @@ -158,5 +146,4 @@ export { subtractHostnameIters, matchesFromHostnames, hostnamesFromMatches, - ubolLog, }; diff --git a/platform/mv3/extension/managed_storage.json b/platform/mv3/extension/managed_storage.json index 8571f59dbaef4..9fb3be661a1b1 100644 --- a/platform/mv3/extension/managed_storage.json +++ b/platform/mv3/extension/managed_storage.json @@ -10,6 +10,18 @@ "disableFirstRunPage": { "title": "Disable first run page", "type": "boolean" + }, + "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" } } } } diff --git a/platform/mv3/extension/matched-rules.html b/platform/mv3/extension/matched-rules.html new file mode 100644 index 0000000000000..488e150a3079e --- /dev/null +++ b/platform/mv3/extension/matched-rules.html @@ -0,0 +1,32 @@ + + + + + +Matched rules + + + + + + + + + + +
+
+ + + + + + + + + diff --git a/platform/mv3/extension/popup.html b/platform/mv3/extension/popup.html index 7492469bd0290..fc2307a99c623 100644 --- a/platform/mv3/extension/popup.html +++ b/platform/mv3/extension/popup.html @@ -13,6 +13,7 @@ +
­
@@ -29,8 +30,9 @@ - - cogs + list-altShow matched rules + comment-alt + cogs
diff --git a/platform/mv3/extension/report.html b/platform/mv3/extension/report.html new file mode 100644 index 0000000000000..21997e936eefc --- /dev/null +++ b/platform/mv3/extension/report.html @@ -0,0 +1,61 @@ + + + + + +uBO Lite — Report + + + + + + + + + + +
+ +

+

+
+
+

+ +
+
+
+

+
+ +

+

+
+ +

+

+ +

+ +
+ +
+ + + + + + + + diff --git a/platform/mv3/firefox/manifest.json b/platform/mv3/firefox/manifest.json index 723ef0fc8ba5b..703f652b28ec0 100644 --- a/platform/mv3/firefox/manifest.json +++ b/platform/mv3/firefox/manifest.json @@ -16,10 +16,10 @@ "browser_specific_settings": { "gecko": { "id": "uBOLite@raymondhill.net", - "strict_min_version": "114.0" + "strict_min_version": "127.0" }, "gecko_android": { - "strict_min_version": "114.0" + "strict_min_version": "127.0" } }, "declarative_net_request": { @@ -37,6 +37,7 @@ "manifest_version": 3, "name": "__MSG_extName__", "options_ui": { + "open_in_tab": true, "page": "dashboard.html" }, "optional_permissions": [ @@ -49,6 +50,5 @@ "storage" ], "short_name": "uBO Lite", - "version": "1.0", - "web_accessible_resources": [] + "version": "1.0" } diff --git a/platform/mv3/make-rulesets.js b/platform/mv3/make-rulesets.js index fd842db38eaa5..f2c62671f359e 100644 --- a/platform/mv3/make-rulesets.js +++ b/platform/mv3/make-rulesets.js @@ -19,19 +19,17 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; +import * as makeScriptlet from './make-scriptlets.js'; +import * as sfp from './js/static-filtering-parser.js'; -/******************************************************************************/ +import { createHash, randomBytes } from 'crypto'; +import { dnrRulesetFromRawLists } from './js/static-dnr-filtering.js'; import fs from 'fs/promises'; import https from 'https'; import path from 'path'; import process from 'process'; -import { createHash, randomBytes } from 'crypto'; import redirectResourcesMap from './js/redirect-resources.js'; -import { dnrRulesetFromRawLists } from './js/static-dnr-filtering.js'; -import * as sfp from './js/static-filtering-parser.js'; -import * as makeScriptlet from './make-scriptlets.js'; import { safeReplace } from './safe-replace.js'; /******************************************************************************/ @@ -85,11 +83,6 @@ const uidint32 = (s) => { return parseInt(h,16) & 0x7FFFFFFF; }; -const hnSort = (a, b) => - a.split('.').reverse().join('.').localeCompare( - b.split('.').reverse().join('.') - ); - /******************************************************************************/ const stdOutput = []; @@ -106,8 +99,7 @@ const log = (text, silent = false) => { const urlToFileName = url => { return url .replace(/^https?:\/\//, '') - .replace(/\//g, '_') - ; + .replace(/\//g, '_'); }; const fetchText = (url, cacheDir) => { @@ -228,7 +220,7 @@ const isRegex = rule => rule.condition.regexFilter !== undefined; const isRedirect = rule => { - if ( rule.action === undefined ) { return false; } + 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; } @@ -236,19 +228,26 @@ const isRedirect = rule => { }; const isModifyHeaders = rule => - rule.action !== undefined && + isUnsupported(rule) === false && rule.action.type === 'modifyHeaders'; const isRemoveparam = rule => - rule.action !== undefined && + isUnsupported(rule) === false && rule.action.type === 'redirect' && rule.action.redirect.transform !== undefined; -const isGood = rule => +const isSafe = rule => + isUnsupported(rule) === false && + rule.action !== undefined && ( + rule.action.type === 'block' || + rule.action.type === 'allow' || + rule.action.type === 'allowAllRequests' + ); + +const isURLSkip = rule => isUnsupported(rule) === false && - isRedirect(rule) === false && - isModifyHeaders(rule) === false && - isRemoveparam(rule) === false; + rule.action !== undefined && + rule.action.type === 'urlskip'; /******************************************************************************/ @@ -360,16 +359,15 @@ async function processNetworkFilters(assetDetails, network) { } } - const plainGood = rules.filter(rule => isGood(rule) && isRegex(rule) === false); + const plainGood = rules.filter(rule => isSafe(rule) && isRegex(rule) === false); log(`\tPlain good: ${plainGood.length}`); log(plainGood .filter(rule => Array.isArray(rule._warning)) .map(rule => rule._warning.map(v => `\t\t${v}`)) - .join('\n'), - true + .join('\n'), true ); - const regexes = rules.filter(rule => isGood(rule) && isRegex(rule)); + const regexes = rules.filter(rule => isSafe(rule) && isRegex(rule)); log(`\tMaybe good (regexes): ${regexes.length}`); const redirects = rules.filter(rule => @@ -398,6 +396,22 @@ async function processNetworkFilters(assetDetails, network) { ); log(`\tmodifyHeaders=: ${modifyHeaders.length}`); + const urlskips = rules.filter(rule => isURLSkip(rule)).filter(rule => + rule.__modifierAction === 0 && + rule.condition && + rule.condition.regexFilter && + rule.condition.resourceTypes && + rule.condition.resourceTypes.includes('main_frame') + ).map(rule => { + const steps = rule.__modifierValue; + return { + re: rule.condition.regexFilter, + c: rule.condition.isUrlFilterCaseSensitive, + steps: steps.includes(' ') && steps.split(/ +/) || [ steps ], + }; + }); + log(`\turlskip=: ${urlskips.length}`); + const bad = rules.filter(rule => isUnsupported(rule) ); @@ -437,6 +451,40 @@ async function processNetworkFilters(assetDetails, network) { ); } + const strictBlocked = new Set(); + for ( const rule of plainGood ) { + if ( rule.action.type !== 'block' ) { continue; } + if ( rule.condition.domainType ) { continue; } + if ( rule.condition.regexFilter ) { continue; } + if ( rule.condition.urlFilter ) { continue; } + if ( rule.condition.requestMethods ) { continue; } + if ( rule.condition.excludedRequestMethods ) { continue; } + if ( rule.condition.resourceTypes ) { continue; } + if ( rule.condition.excludedResourceTypes ) { continue; } + if ( rule.condition.responseHeaders ) { continue; } + if ( rule.condition.excludedResponseHeaders ) { continue; } + if ( rule.condition.initiatorDomains ) { continue; } + if ( rule.condition.excludedInitiatorDomains ) { continue; } + if ( rule.condition.requestDomains === undefined ) { continue; } + if ( rule.condition.excludedRequestDomains ) { continue; } + for ( const hn of rule.condition.requestDomains ) { + strictBlocked.add(hn); + } + } + if ( strictBlocked.size !== 0 ) { + writeFile( + `${rulesetDir}/strictblock/${assetDetails.id}.json`, + toJSONRuleset(Array.from(strictBlocked)) + ); + } + + if ( urlskips.length !== 0 ) { + writeFile( + `${rulesetDir}/urlskip/${assetDetails.id}.json`, + JSON.stringify(urlskips, null, 1) + ); + } + return { total: rules.length, plain: plainGood.length, @@ -446,6 +494,8 @@ async function processNetworkFilters(assetDetails, network) { removeparam: removeparamsGood.length, redirect: redirects.length, modifyHeaders: modifyHeaders.length, + strictblock: strictBlocked.size, + urlskip: urlskips.length, }; } @@ -626,14 +676,10 @@ function groupHostnamesBySelectors(arrayin) { const out = Array.from(contentMap).map(a => [ a[0], { a: a[1].a, - y: a[1].y ? Array.from(a[1].y).sort(hnSort) : '*', + y: a[1].y ? Array.from(a[1].y) : undefined, n: a[1].n ? Array.from(a[1].n) : undefined, } - ]).sort((a, b) => { - const ha = Array.isArray(a[1].y) ? a[1].y[0] : '*'; - const hb = Array.isArray(b[1].y) ? b[1].y[0] : '*'; - return hnSort(ha, hb); - }); + ]); return out; } @@ -1072,8 +1118,10 @@ async function rulesetFromURLs(assetDetails) { id: assetDetails.id, name: assetDetails.name, group: assetDetails.group, + parent: assetDetails.parent, enabled: assetDetails.enabled, lang: assetDetails.lang, + tags: assetDetails.tags, homeURL: assetDetails.homeURL, filters: { total: results.network.filterCount, @@ -1087,6 +1135,8 @@ async function rulesetFromURLs(assetDetails) { removeparam: netStats.removeparam, redirect: netStats.redirect, modifyHeaders: netStats.modifyHeaders, + strictblock: netStats.strictblock, + urlskip: netStats.urlskip, discarded: netStats.discarded, rejected: netStats.rejected, }, @@ -1125,7 +1175,7 @@ async function main() { // Get assets.json content const assets = await fs.readFile( - `./assets.json`, + `./assets.dev.json`, { encoding: 'utf8' } ).then(text => JSON.parse(text) @@ -1136,68 +1186,28 @@ async function main() { log(`Secret: ${secret}`); // Assemble all default lists as the default ruleset - const contentURLs = [ - 'https://ublockorigin.github.io/uAssets/filters/filters.min.txt', - 'https://ublockorigin.github.io/uAssets/filters/badware.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', - ]; await rulesetFromURLs({ id: 'default', name: 'Ads, trackers, miners, and more' , enabled: true, secret, - urls: contentURLs, + urls: [ + 'https://ublockorigin.github.io/uAssets/filters/filters.min.txt', + 'https://ublockorigin.github.io/uAssets/filters/badware.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: [ ], }); - // 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 ( typeof asset.lang !== 'string' ) { continue; } - if ( excludedLists.includes(id) ) { continue; } - let ids = langToListsMap.get(asset.lang); - if ( ids === undefined ) { - langToListsMap.set(asset.lang, 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]; - await rulesetFromURLs({ - id: id.toLowerCase(), - lang: asset.lang, - name: asset.title, - enabled: false, - urls, - homeURL: asset.supportURL, - }); - } - // Handpicked rulesets from assets.json const handpicked = [ 'block-lan', @@ -1276,14 +1286,95 @@ async function main() { }); // 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: false, + urls: [ + 'https://raw.githubusercontent.com/stephenhawk8054/openphish-adblock/refs/heads/main/filters_init_domains.txt', + ], + filters: [ + ], + homeURL: 'https://github.com/stephenhawk8054/openphish-adblock', + }); + await rulesetFromURLs({ id: 'stevenblack-hosts', - name: 'Steven Black\'s hosts file', + 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`, `${JSON.stringify(rulesetDetails, null, 1)}\n` @@ -1317,6 +1408,15 @@ async function main() { // Patch declarative_net_request key manifest.declarative_net_request = { rule_resources: ruleResources }; // Patch web_accessible_resources key + manifest.web_accessible_resources = manifest.web_accessible_resources || []; + // Strict-block-related resource + const strictblockDocument = `strictblock.${secret}.html`; + copyFile('./strictblock.html', `${outputDir}/${strictblockDocument}`); + manifest.web_accessible_resources.push({ + resources: [ `/${strictblockDocument}` ], + matches: [ '' ], + }); + // Secondary resources const web_accessible_resources = { resources: Array.from(requiredRedirectResources).map(path => `/${path}`), matches: [ '' ], @@ -1324,7 +1424,7 @@ async function main() { if ( platform === 'chromium' ) { web_accessible_resources.use_dynamic_url = true; } - manifest.web_accessible_resources = [ web_accessible_resources ]; + manifest.web_accessible_resources.push(web_accessible_resources); // Patch manifest version property manifest.version = version; @@ -1336,7 +1436,7 @@ async function main() { // Log results const logContent = stdOutput.join('\n') + '\n'; - await fs.writeFile(`${cacheDir}/log.txt`, logContent); + await fs.writeFile(`${outputDir}/log.txt`, logContent); } main(); diff --git a/platform/mv3/make-scriptlets.js b/platform/mv3/make-scriptlets.js index d276a56a6ace4..27dc5d247921b 100644 --- a/platform/mv3/make-scriptlets.js +++ b/platform/mv3/make-scriptlets.js @@ -19,12 +19,8 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - +import { builtinScriptlets } from './js/resources/scriptlets.js'; import fs from 'fs/promises'; -import { builtinScriptlets } from './scriptlets.js'; import { safeReplace } from './safe-replace.js'; /******************************************************************************/ diff --git a/platform/mv3/scriptlets/scriptlet.template.js b/platform/mv3/scriptlets/scriptlet.template.js index f5a47483b5ec8..19560c8aedbef 100644 --- a/platform/mv3/scriptlets/scriptlet.template.js +++ b/platform/mv3/scriptlets/scriptlet.template.js @@ -20,10 +20,7 @@ */ -/* jshint esversion:11 */ -/* global cloneInto */ - -'use strict'; +/* eslint-disable indent */ // ruleset: $rulesetId$ @@ -40,7 +37,7 @@ // Start of code to inject const uBOL_$scriptletName$ = function() { -const scriptletGlobals = {}; // jshint ignore: line +const scriptletGlobals = {}; // eslint-disable-line const argsList = self.$argsList$; @@ -57,7 +54,19 @@ function $scriptletName$(){} /******************************************************************************/ const hnParts = []; -try { hnParts.push(...document.location.hostname.split('.')); } +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 pos = origin.lastIndexOf('://'); + if ( pos === -1 ) { return; } + hnParts.push(...origin.slice(pos+3).split('.')); +} catch(ex) { } const hnpartslen = hnParts.length; if ( hnpartslen === 0 ) { return; } @@ -126,44 +135,7 @@ argsList.length = 0; /******************************************************************************/ -// Inject code - -// https://bugzilla.mozilla.org/show_bug.cgi?id=1736575 -// 'MAIN' world not yet supported in Firefox, so we inject the code into -// 'MAIN' ourself when environment in Firefox. - -const targetWorld = '$world$'; - -// Not Firefox -if ( typeof wrappedJSObject !== 'object' || targetWorld === 'ISOLATED' ) { - return uBOL_$scriptletName$(); -} - -// Firefox -{ - const page = self.wrappedJSObject; - let script, url; - try { - page.uBOL_$scriptletName$ = cloneInto([ - [ '(', uBOL_$scriptletName$.toString(), ')();' ], - { type: 'text/javascript; charset=utf-8' }, - ], self); - const blob = new page.Blob(...page.uBOL_$scriptletName$); - url = page.URL.createObjectURL(blob); - const doc = page.document; - script = doc.createElement('script'); - script.async = false; - script.src = url; - (doc.head || doc.documentElement || doc).append(script); - } catch (ex) { - console.error(ex); - } - if ( url ) { - if ( script ) { script.remove(); } - page.URL.revokeObjectURL(url); - } - delete page.uBOL_$scriptletName$; -} +uBOL_$scriptletName$(); /******************************************************************************/ diff --git a/platform/mv3/strictblock.html b/platform/mv3/strictblock.html new file mode 100644 index 0000000000000..8b6ef2d9be94b --- /dev/null +++ b/platform/mv3/strictblock.html @@ -0,0 +1,49 @@ + + + + + + + + + + + + + +
+ + +
+

+ +
+ + + + + +
+ +
+ +
+ + + +
+
+ + + + + + + diff --git a/platform/mv3/ubo-version b/platform/mv3/ubo-version deleted file mode 100644 index 4437cefd15cb1..0000000000000 --- a/platform/mv3/ubo-version +++ /dev/null @@ -1 +0,0 @@ -https://github.com/gorhill/uBlock/tree/4b83101ab9270a5403d66af4ebe08d251ac372ca diff --git a/platform/nodejs/.eslintrc.json b/platform/nodejs/.eslintrc.json new file mode 100644 index 0000000000000..5f7c6b58c5ccf --- /dev/null +++ b/platform/nodejs/.eslintrc.json @@ -0,0 +1,38 @@ +{ + "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 --git a/platform/nodejs/index.js b/platform/nodejs/index.js index 1d39a7d11292e..56aa74f42c67c 100644 --- a/platform/nodejs/index.js +++ b/platform/nodejs/index.js @@ -19,31 +19,40 @@ Home: https://github.com/gorhill/uBlock */ -/* globals WebAssembly */ - -'use strict'; +import * as s14e from './js/s14e-serializer.js'; +import * as sfp from './js/static-filtering-parser.js'; -/******************************************************************************/ +import { + CompiledListReader, + CompiledListWriter, +} from './js/static-filtering-io.js'; +import { + TextDecoder, + TextEncoder, +} from 'util'; +import { + dirname, + resolve +} from 'path'; +import { + domainToASCII, + fileURLToPath +} from 'url'; +import { FilteringContext } from './js/filtering-context.js'; +import { LineIterator } from './js/text-utils.js'; import { createRequire } from 'module'; - +import publicSuffixList from './lib/publicsuffixlist/publicsuffixlist.js'; import { readFileSync } from 'fs'; -import { dirname, resolve } from 'path'; -import { domainToASCII, fileURLToPath } from 'url'; - -const __dirname = dirname(fileURLToPath(import.meta.url)); +import snfe from './js/static-net-filtering.js'; -import publicSuffixList from './lib/publicsuffixlist/publicsuffixlist.js'; +/******************************************************************************/ -import snfe 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'; +const __dirname = dirname(fileURLToPath(import.meta.url)); -import { - CompiledListReader, - CompiledListWriter, -} from './js/static-filtering-io.js'; +// https://stackoverflow.com/questions/69187442/const-utf8encoder-new-textencoder-in-node-js +globalThis.TextDecoder = TextDecoder; +globalThis.TextEncoder = TextEncoder; /******************************************************************************/ @@ -110,6 +119,7 @@ function pslInit(raw) { /******************************************************************************/ function compileList({ name, raw }, compiler, writer, options = {}) { + if ( typeof raw !== 'string' || raw === '' ) { return; } const lineIter = new LineIterator(raw); const events = Array.isArray(options.events) ? options.events : undefined; @@ -173,8 +183,7 @@ async function useLists(lists, options = {}) { // Populate filtering engine with resolved filter lists const promises = []; for ( const list of lists ) { - const promise = list instanceof Promise ? list : Promise.resolve(list); - promises.push(promise.then(list => consumeList(list))); + promises.push(Promise.resolve(list).then(list => consumeList(list))); } useLists.promise = Promise.all(promises); @@ -218,6 +227,7 @@ class StaticNetFilteringEngine { } filterQuery(details) { + fctx.redirectURL = undefined; const directives = snfe.filterQuery(fctx.fromDetails(details)); if ( directives === undefined ) { return; } return { redirectURL: fctx.redirectURL, directives }; @@ -239,12 +249,14 @@ class StaticNetFilteringEngine { return compileList(...args); } - serialize() { - return snfe.serialize(); + async serialize() { + const data = snfe.serialize(); + return s14e.serialize(data, { compress: true }); } - deserialize(serialized) { - return snfe.unserialize(serialized); + async deserialize(serialized) { + const data = s14e.deserialize(serialized); + return snfe.unserialize(data); } static async create({ noPSL = false } = {}) { diff --git a/platform/nodejs/README.md b/platform/npm/README.md similarity index 86% rename from platform/nodejs/README.md rename to platform/npm/README.md index 0b3e3d8c074dc..a1ce7f42e7004 100644 --- a/platform/nodejs/README.md +++ b/platform/npm/README.md @@ -27,6 +27,8 @@ and also lists of domain names or hosts file format (i.e. block lists from [The ## Usage +See `./demo.js` in package for instructions to quickly get started. + At the moment, there can be only one instance of the static network filtering engine ("SNFE"), which proxy API must be imported as follow: @@ -44,7 +46,7 @@ const { StaticNetFilteringEngine } = await import('@gorhill/ubo-core'); Create an instance of SNFE: ```js -const snfe = StaticNetFilteringEngine.create(); +const snfe = await StaticNetFilteringEngine.create(); ``` Feed the SNFE with filter lists -- `useLists()` accepts an array of @@ -54,8 +56,8 @@ through the `raw` property, and optionally the name of the list through the ```js await snfe.useLists([ - fetch('easylist').then(raw => ({ name: 'easylist', raw })), - fetch('easyprivacy').then(raw => ({ name: 'easyprivacy', raw })), + fetch('easylist').then(r => r.text()).then(raw => ({ name: 'easylist', raw })), + fetch('easyprivacy').then(r => r.text()).then(raw => ({ name: 'easyprivacy', raw })), ]); ``` @@ -90,10 +92,20 @@ if ( snfe.matchRequest({ } ``` -It is possible to pre-parse filter lists and save the intermediate results for -later use -- useful to speed up the loading of filter lists. This will be -documented eventually, but if you feel adventurous, you can look at the code -and use this capability now if you figure out the details. +Once all the filter lists are loaded into the static network filtering engine, +you can serialize the content of the engine into a JS string: + +```js +const serializedData = await snfe.serialize(); +``` + +You can save and later use that JS string to fast-load the content of the +static network filtering engine without having to parse and compile the lists: + +```js +const snfe = await StaticNetFilteringEngine.create(); +await snfe.deserialize(serializedData); +``` --- diff --git a/platform/npm/demo.js b/platform/npm/demo.js new file mode 100644 index 0000000000000..bc0ca87a1f7e3 --- /dev/null +++ b/platform/npm/demo.js @@ -0,0 +1,121 @@ +/******************************************************************************* + * + * A simple demo to quickly get started. + * + * Command line: + * + * mkdir myproject + * cd myproject + * npm install @gorhill/ubo-core + * cp node_modules/@gorhill/ubo-core/demo.js . + * + * There will be a `demo.js` file in your `myproject` folder, which you can + * modify and execute: + * + * node demo.js + * + * Since the demo here uses ES module syntax, you may want to add the following + * to the generated package.json file to avoid the warning: + * + * "type": "module", + * + * The demo will fetch filter lists from EasyList server, then serialize the + * content of the static network filtering engine into a local `./cache/` + * folder. + * + * The serialized data will be reused if available in order to avoid fetching + * from remote server each time it is executed. + * + * This demo is kept as simple as possible, so there is not a lot of error + * handling. + * + * */ + +import fs from 'fs/promises'; +import { StaticNetFilteringEngine } from '@gorhill/ubo-core'; + +/******************************************************************************/ + +async function fetchList(name, url) { + return fetch(url).then(r => { + return r.text(); + }).then(raw => { + console.log(`${name} fetched`); + return { name, raw }; + }).catch(reason => { + console.error(reason); + }); +} + +async function main() { + const pathToSelfie = 'cache/selfie.txt'; + + const snfe = await StaticNetFilteringEngine.create(); + + // Up to date serialization data (aka selfie) available? + let selfie; + const ageInDays = await fs.stat(pathToSelfie).then(stat => { + const fileDate = new Date(stat.mtime); + return (Date.now() - fileDate.getTime()) / (7 * 24 * 60 * 60); + }).catch(( ) => Number.MAX_SAFE_INTEGER); + + // Use a selfie if available and not older than 7 days + if ( ageInDays <= 7 ) { + selfie = await fs.readFile(pathToSelfie, { encoding: 'utf8' }) + .then(data => typeof data === 'string' && data !== '' && data) + .catch(( ) => { }); + if ( typeof selfie === 'string' ) { + await snfe.deserialize(selfie); + } + } + + // Fetch filter lists if no up to date selfie available + if ( !selfie ) { + console.log(`Fetching lists...`); + await snfe.useLists([ + fetchList('ubo-ads', 'https://ublockorigin.github.io/uAssetsCDN/filters/filters.min.txt'), + fetchList('ubo-badware', 'https://ublockorigin.github.io/uAssetsCDN/filters/badware.min.txt'), + fetchList('ubo-privacy', 'https://ublockorigin.github.io/uAssetsCDN/filters/privacy.min.txt'), + fetchList('ubo-unbreak', 'https://ublockorigin.github.io/uAssetsCDN/filters/unbreak.min.txt'), + fetchList('ubo-quick', 'https://ublockorigin.github.io/uAssetsCDN/filters/quick-fixes.min.txt'), + fetchList('easylist', 'https://easylist.to/easylist/easylist.txt'), + fetchList('easyprivacy', 'https://easylist.to/easylist/easyprivacy.txt'), + fetchList('plowe', 'https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=1&mimetype=plaintext'), + ]); + const selfie = await snfe.serialize(); + await fs.mkdir('cache', { recursive: true }); + await fs.writeFile(pathToSelfie, selfie); + } + + // List of tests to perform + const tests = [ + { + originURL: 'https://www.bloomberg.com/', + url: 'https://www.google-analytics.com/gs.js', + type: 'script', + }, { + originURL: 'https://www.bloomberg.com/', + url: 'https://securepubads.g.doubleclick.net/tag/js/gpt.js', + type: 'script', + }, { + originURL: 'https://www.bloomberg.com/', + url: 'https://bloomberg.com/main.css', + type: 'stylesheet', + } + ]; + + // Test each entry for a match against the content of the engine + for ( const test of tests ) { + console.log('\nRequest details:', test); + const r = snfe.matchRequest(test); + if ( r === 1 ) { // Blocked + console.log('Blocked:', snfe.toLogData()); + } else if ( r === 2 ) { // Unblocked + console.log('Unblocked:', snfe.toLogData()); + } else { // Not blocked + console.log('Not blocked'); + } + } +} + +main(); diff --git a/platform/npm/package-lock.json b/platform/npm/package-lock.json index b819bb0fddb68..3a1790e27a906 100644 --- a/platform/npm/package-lock.json +++ b/platform/npm/package-lock.json @@ -242,12 +242,15 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "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.0.1" + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" } }, "node_modules/browser-stdout": { @@ -683,12 +686,15 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "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": { @@ -892,7 +898,10 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.12.0" + } }, "node_modules/is-path-inside": { "version": "3.0.3", @@ -1062,15 +1071,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -1398,6 +1398,15 @@ "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", @@ -1481,6 +1490,9 @@ "dev": true, "dependencies": { "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" } }, "node_modules/type-check": { @@ -1537,10 +1549,13 @@ } }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true + "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", @@ -1818,12 +1833,12 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "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.0.1" + "fill-range": "^7.1.1" } }, "browser-stdout": { @@ -2202,9 +2217,9 @@ } }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "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" @@ -2532,14 +2547,6 @@ "dev": true, "requires": { "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } } }, "minimatch": { @@ -2808,6 +2815,12 @@ "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", @@ -2935,9 +2948,9 @@ } }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true }, "workerpool": { diff --git a/platform/npm/package.json b/platform/npm/package.json index a505449e624f6..6430bec8e52c9 100644 --- a/platform/npm/package.json +++ b/platform/npm/package.json @@ -1,6 +1,6 @@ { "name": "@gorhill/ubo-core", - "version": "0.1.26", + "version": "0.1.30", "description": "To create a working instance of uBlock Origin's static network filtering engine", "type": "module", "main": "index.js", @@ -31,7 +31,7 @@ }, "homepage": "https://github.com/gorhill/uBlock#readme", "engines": { - "node": ">=14.0.0", + "node": ">=18.0.0", "npm": ">=6.14.4" }, "devDependencies": { diff --git a/platform/opera/manifest.json b/platform/opera/manifest.json index 196c171726670..38015c3959979 100644 --- a/platform/opera/manifest.json +++ b/platform/opera/manifest.json @@ -88,7 +88,7 @@ }, "incognito": "split", "manifest_version": 2, - "minimum_opera_version": "60.0", + "minimum_opera_version": "67.0", "name": "uBlock Origin", "options_page": "dashboard.html", "permissions": [ diff --git a/src/_locales/ar/messages.json b/src/_locales/ar/messages.json index b2c204d3abefd..3d1023f561df5 100644 --- a/src/_locales/ar/messages.json +++ b/src/_locales/ar/messages.json @@ -312,7 +312,7 @@ "description": "English: Click, Ctrl-click" }, "pickerContextMenuEntry": { - "message": "إحجب العنصر...", + "message": "حجب العنصر...", "description": "An entry in the browser's contextual menu" }, "settingsCollapseBlockedPrompt": { @@ -1011,6 +1011,10 @@ "message": "افتح التبويبات أو النوافذ التي ليس مرغوبًا بها", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "يؤدي إلى البرامج الضارة والإحتيال", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "تسمية صفحة الويب باسم \"NSFW\" (\"ليس آمن للعمل\"\n", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "تقدّم", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "الصفحة المحظورة تريد إعادة توجيهك إلى موقع آخر. إذا اخترت المتابعة، فسوف تنتقل مباشرة إلى: {{url}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "التصدير إلى سحابة التخزين", "description": "tooltip" @@ -1244,7 +1252,7 @@ "description": "A context menu entry, to view the source code of the target resource" }, "shortcutCapturePlaceholder": { - "message": "ادخل اختصار", + "message": "أدخِل اختصار", "description": "Placeholder string for input field used to capture a keyboard shortcut" }, "genericMergeViewScrollLock": { diff --git a/src/_locales/az/messages.json b/src/_locales/az/messages.json index 1708ea47e5954..13549bd06b28d 100644 --- a/src/_locales/az/messages.json +++ b/src/_locales/az/messages.json @@ -1011,6 +1011,10 @@ "message": "Arzuolunmaz tab-vərəqələr və ya pəncərələr açır", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Veb-səhifəni uyğun olmayan (“NSFW”) olaraq işarələ (“Not Safe For Work”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Davam et", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Bulud yaddaşa göndər", "description": "tooltip" diff --git a/src/_locales/be/messages.json b/src/_locales/be/messages.json index bb7a458505742..43aef84b7a2ff 100644 --- a/src/_locales/be/messages.json +++ b/src/_locales/be/messages.json @@ -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" }, "dashboardName": { @@ -1011,6 +1011,10 @@ "message": "Адкрывае непажаданыя карткі або вокны", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Вядзе да шкодных праграм, фішынгу", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Пазначыць вэб-старонку як “NSFW” (“Not Safe For Work”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Працягнуць", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Заблакаваная старонка мае намер перанакіраваць на іншы сайт. Калі вырашыце працягнуць, вы пяройдзеце непасрэдна да: {{url}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Экспартаваць у воблачнае сховішча", "description": "tooltip" diff --git a/src/_locales/bg/messages.json b/src/_locales/bg/messages.json index aaff8db583deb..b5cbeadfab1ab 100644 --- a/src/_locales/bg/messages.json +++ b/src/_locales/bg/messages.json @@ -1011,6 +1011,10 @@ "message": "Отваря нежелани раздели или прозорци", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Води до зловреден софтуер, фишинг", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Маркиране на уеб страницата като “NSFW” (“не е безопасна за работа”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Продължаване", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Блокираната страница иска да Ви пренасочи към друг сайт. Ако изберете да продължите, ще отидете директно на: {{url}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Изнасяне в облачно хранилище", "description": "tooltip" diff --git a/src/_locales/bn/messages.json b/src/_locales/bn/messages.json index de82ca4dee471..13aa3ac653e1f 100644 --- a/src/_locales/bn/messages.json +++ b/src/_locales/bn/messages.json @@ -1011,6 +1011,10 @@ "message": "অবাঞ্ছিত ট্যাব বা উইন্ডো খোলে", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "ওয়েব পৃষ্ঠাটিকে “NSFW” হিসাবে লেবেল করুন (“কাজের জন্য নিরাপদ নয়”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "ক্লাউড সঞ্চয়ে রপ্তানি করুন", "description": "tooltip" diff --git a/src/_locales/br_FR/messages.json b/src/_locales/br_FR/messages.json index 2a27e9f019281..53d3ce41e38c9 100644 --- a/src/_locales/br_FR/messages.json +++ b/src/_locales/br_FR/messages.json @@ -12,7 +12,7 @@ "description": "English: uBlock₀ — Dashboard" }, "dashboardUnsavedWarning": { - "message": "Diwallit! Kemmoù zo ha n'ho peus enrollet anezho", + "message": "Diwallit! Kemmoù zo ha n'ho peus ket enrollet", "description": "A warning in the dashboard when navigating away from unsaved changes" }, "dashboardUnsavedWarningStay": { @@ -156,15 +156,15 @@ "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoCosmeticFiltering": { - "message": "Lazhañ/enaouiñ ar silañ kenedel war al lec'hienn-mañ", + "message": "Lazhañ/enaouiñ ar siloù kenedel war al lec'hienn-mañ", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoCosmeticFiltering1": { - "message": "Lazhañ ar silañ kenedel war al lec'hienn-mañ", + "message": "Lazhañ ar siloù kenedel war al lec'hienn-mañ", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoCosmeticFiltering2": { - "message": "Enaouiñ ar silañ kenedel war al lec'hienn-mañ", + "message": "Enaouiñ ar siloù kenedel war al lec'hienn-mañ", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoRemoteFonts": { @@ -376,7 +376,7 @@ "description": "" }, "settingsNoCosmeticFilteringPrompt": { - "message": "Lazhañ ar silañ kenedel", + "message": "Lazhañ ar siloù kenedel", "description": "" }, "settingsNoLargeMediaPrompt": { @@ -484,11 +484,11 @@ "description": "Filter lists section name" }, "3pGroupSocial": { - "message": "Social widgets", + "message": "Widgetoù sokial", "description": "Filter lists section name" }, "3pGroupCookies": { - "message": "Cookie notices", + "message": "Kemennadennoù diwar-benn an toupinoù", "description": "Filter lists section name" }, "3pGroupAnnoyances": { @@ -1011,6 +1011,10 @@ "message": "Digeriñ a ra ivinelloù pe prenestroù noazus", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Merkañ ar bejenn evel \"NSFW\" (“Not Safe For Work”) hag a dalv ez eus danvez noazus pe kizidik enni", "description": "A checkbox to use for NSFW sites" @@ -1156,7 +1160,7 @@ "description": "label to be used for the parameter-less URL: https://cloud.githubusercontent.com/assets/585534/9832014/bfb1b8f0-593b-11e5-8a27-fba472a5529a.png" }, "docblockedFoundIn": { - "message": "Hag a vez kavet e-barzh:", + "message": "Hag a zo kavet e-barzh:", "description": "English: List of filter list names follows" }, "docblockedBack": { @@ -1187,6 +1191,10 @@ "message": "Kenderc'hel", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Ezporzhiañ etrezek stokañ ar goumoulenn (cloud)", "description": "tooltip" @@ -1260,7 +1268,7 @@ "description": "Label for buttons used to select all text in editor" }, "toggleCosmeticFiltering": { - "message": "Enaouiñ ar silañ kenedel", + "message": "Enaouiñ ar siloù kenedel", "description": "Label for keyboard shortcut used to toggle cosmetic filtering" }, "toggleJavascript": { diff --git a/src/_locales/bs/messages.json b/src/_locales/bs/messages.json index d80ae9d7bb8ef..d8464590ffc60 100644 --- a/src/_locales/bs/messages.json +++ b/src/_locales/bs/messages.json @@ -484,11 +484,11 @@ "description": "Filter lists section name" }, "3pGroupSocial": { - "message": "Social widgets", + "message": "Društveni widgeti", "description": "Filter lists section name" }, "3pGroupCookies": { - "message": "Cookie notices", + "message": "Obavještenja o kolačićima", "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": "Omogući moje prilagođene filtere", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { - "message": "Allow custom filters requiring trust", + "message": "Dozvolite prilagođene filtere koji zahtijevaju povjerenje", "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { @@ -1011,6 +1011,10 @@ "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", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Označite web stranicu kao “NSZP” (“Ne-Sigurna-Za-Posao”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Nastavi", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Izvezi u cloud pohranu", "description": "tooltip" @@ -1264,7 +1272,7 @@ "description": "Label for keyboard shortcut used to toggle cosmetic filtering" }, "toggleJavascript": { - "message": "Toggle JavaScript", + "message": "Uključi JavaScript", "description": "Label for keyboard shortcut used to toggle no-scripting switch" }, "relaxBlockingMode": { diff --git a/src/_locales/ca/messages.json b/src/_locales/ca/messages.json index 97ade2de31ecf..e2f4623328e4f 100644 --- a/src/_locales/ca/messages.json +++ b/src/_locales/ca/messages.json @@ -1011,6 +1011,10 @@ "message": "Obre pestanyes o finestres no desitjades", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Condueix a programari maliciós, pesca electrònica", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Marca aquesta pàgina com a “NSFW” (“No segur per al treball”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Procedeix", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Exporta a un servei al núvol", "description": "tooltip" @@ -1264,7 +1272,7 @@ "description": "Label for keyboard shortcut used to toggle cosmetic filtering" }, "toggleJavascript": { - "message": "Canviar l'estat de JavaScript", + "message": "Commuta el JavaScript", "description": "Label for keyboard shortcut used to toggle no-scripting switch" }, "relaxBlockingMode": { diff --git a/src/_locales/cs/messages.json b/src/_locales/cs/messages.json index 025f0b59a868c..f2c26a6c8ae31 100644 --- a/src/_locales/cs/messages.json +++ b/src/_locales/cs/messages.json @@ -928,7 +928,7 @@ "description": "Header of 'Filter issues' section in Support pane" }, "supportS3P1": { - "message": "Hlášení problémů s filtrem u učitých web. stránek do uBlockOrigin/uAssets issue tracker. Vyžaduje účet GitHub.", + "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" }, "supportS3P2": { @@ -1011,8 +1011,12 @@ "message": "Otevírá nechtěné karty nebo okna", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Vede k badwaru, phishingu", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { - "message": "Označit webovou stránku jako “NSFW” (Není bezpečné pro práci”)", + "message": "Označit webovou stránku jako “NSFW” (“Není bezpečné pro práci”)", "description": "A checkbox to use for NSFW sites" }, "supportRedact": { @@ -1187,6 +1191,10 @@ "message": "Pokračovat", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Exportovat do cloudového úložiště", "description": "tooltip" diff --git a/src/_locales/cv/messages.json b/src/_locales/cv/messages.json index aec33ebe8dfc8..b648059a7aed4 100644 --- a/src/_locales/cv/messages.json +++ b/src/_locales/cv/messages.json @@ -1011,6 +1011,10 @@ "message": "Opens unwanted tabs or windows", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "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”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Proceed", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff --git a/src/_locales/cy/messages.json b/src/_locales/cy/messages.json index 7152ef93ed9dd..02cfc802feb66 100644 --- a/src/_locales/cy/messages.json +++ b/src/_locales/cy/messages.json @@ -4,15 +4,15 @@ "description": "extension name." }, "extShortDesc": { - "message": "O'r diwedd, rhwystrydd effeithlon. Ysgafn ar y CPU a'r cof.", + "message": "O'r diwedd, rhwystrydd effeithlon sy'n gwell ar y CPU a'r cof.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "dashboardName": { - "message": "uBlock₀ — Dashfwrdd", + "message": "uBlock₀ — Dangosfwrdd", "description": "English: uBlock₀ — Dashboard" }, "dashboardUnsavedWarning": { - "message": "Rhybudd! Mae yna newidiadau heb eu cadw", + "message": "Rhybudd! Mae gennych newidiadau heb eu cadw", "description": "A warning in the dashboard when navigating away from unsaved changes" }, "dashboardUnsavedWarningStay": { @@ -116,11 +116,11 @@ "description": "English: Click to open the dashboard" }, "popupTipZapper": { - "message": "Modd saethu elfen", + "message": "Galluogi modd saethu elfen", "description": "Tooltip for the element-zapper icon in the popup panel" }, "popupTipPicker": { - "message": "Modd dewis elfen", + "message": "Galluogi modd dewis elfen", "description": "English: Enter element picker mode" }, "popupTipLog": { @@ -208,7 +208,7 @@ "description": "Caption for the no-scripting per-site switch" }, "popupMoreButton_v2": { - "message": "Mwy", + "message": "Rhagor", "description": "Label to be used to show popup panel sections" }, "popupLessButton_v2": { @@ -236,15 +236,15 @@ "description": "" }, "popupImageRulePrompt": { - "message": "images", + "message": "delweddau", "description": "" }, "popup3pAnyRulePrompt": { - "message": "3rd-party", + "message": "3ydd-parti", "description": "" }, "popup3pPassiveRulePrompt": { - "message": "3rd-party CSS/images", + "message": "CSS/delweddau 3ydd-parti", "description": "" }, "popupInlineScriptRulePrompt": { @@ -312,7 +312,7 @@ "description": "English: Click, Ctrl-click" }, "pickerContextMenuEntry": { - "message": "Block element…", + "message": "Blocio elfen…", "description": "An entry in the browser's contextual menu" }, "settingsCollapseBlockedPrompt": { @@ -336,7 +336,7 @@ "description": "English: Color-blind friendly" }, "settingsAppearance": { - "message": "Golwg", + "message": "Gwedd", "description": "Section for controlling user interface appearance" }, "settingsThemeLabel": { @@ -464,11 +464,11 @@ "description": "English: Lists of blocked hosts" }, "3pApplyChanges": { - "message": "Apply changes", + "message": "Rhoi newidiadau ar waith", "description": "English: Apply changes" }, "3pGroupDefault": { - "message": "Built-in", + "message": "Mewnol", "description": "Filter lists section name" }, "3pGroupAds": { @@ -488,7 +488,7 @@ "description": "Filter lists section name" }, "3pGroupCookies": { - "message": "Cookie notices", + "message": "Hysbysiadau cwci", "description": "Filter lists section name" }, "3pGroupAnnoyances": { @@ -520,7 +520,7 @@ "description": "used as a tooltip for the out-of-date icon beside a list" }, "3pViewContent": { - "message": "gweld y cynnwys", + "message": "gweld cynnwys", "description": "used as a tooltip for eye icon beside a list" }, "3pLastUpdate": { @@ -528,7 +528,7 @@ "description": "used as a tooltip for the clock icon beside a list" }, "3pUpdating": { - "message": "Updating…", + "message": "Wrthi'n diweddaru…", "description": "used as a tooltip for the spinner icon beside a list" }, "3pNetworkError": { @@ -940,7 +940,7 @@ "description": "Third paragraph of 'Filter issues' section in Support pane" }, "supportS4H": { - "message": "Bug report", + "message": "Adroddiad nam", "description": "Header of 'Bug report' section in Support pane" }, "supportS4P1": { @@ -1011,6 +1011,10 @@ "message": "Opens unwanted tabs or windows", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "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”)", "description": "A checkbox to use for NSFW sites" @@ -1028,7 +1032,7 @@ "description": "Link to privacy policy on GitHub (English)" }, "aboutChangelog": { - "message": "Changelog", + "message": "Cofnod newidiadau", "description": "" }, "aboutCode": { @@ -1136,7 +1140,7 @@ "description": "Firefox/Fennec-specific: Show Logger" }, "fennecMenuItemBlockingOff": { - "message": "off", + "message": "na", "description": "Firefox-specific: appears as 'uBlock₀ (off)'" }, "docblockedTitle": { @@ -1187,6 +1191,10 @@ "message": "Parhau", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" @@ -1216,15 +1224,15 @@ "description": "for generic 'Submit' buttons" }, "genericApplyChanges": { - "message": "Apply changes", + "message": "Rhoi newidiadau ar waith", "description": "for generic 'Apply changes' buttons" }, "genericRevert": { - "message": "Revert", + "message": "Gwrthdroi", "description": "for generic 'Revert' buttons" }, "genericBytes": { - "message": "bytes", + "message": "beit", "description": "" }, "contextMenuBlockElementInFrame": { diff --git a/src/_locales/da/messages.json b/src/_locales/da/messages.json index 061e781a95026..b737ac367952e 100644 --- a/src/_locales/da/messages.json +++ b/src/_locales/da/messages.json @@ -1011,6 +1011,10 @@ "message": "Åbner uønskede faner eller vinduer", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Fører til badware, phishing", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Markér websiden som “NSFW” (“Ikke sikker til arbejdsbrug”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Fortsæt", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Eksportér til Skylager", "description": "tooltip" diff --git a/src/_locales/de/messages.json b/src/_locales/de/messages.json index 473673525f79d..60289ec911790 100644 --- a/src/_locales/de/messages.json +++ b/src/_locales/de/messages.json @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Neuen Bericht erstellen", + "message": "Neue Meldung erstellen", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Ähnliche Berichte suchen", + "message": "Ähnliche Meldungen finden", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -988,11 +988,11 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { - "message": "Zeigt Werbung oder Anzeigenreste", + "message": "Zeigt Werbung oder Werbereste", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "Enthält Überdeckungen oder andere Belästigungen", + "message": "Hat Überdeckungen oder andere Belästigungen", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { @@ -1011,6 +1011,10 @@ "message": "Öffnet unerwünschte Tabs oder Fenster", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Führt zu Schadsoftware, Phishing", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Webseite als »NSFW« kennzeichnen (»Unpassend für den Arbeitsplatz«)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Fortfahren", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "In den Cloud-Speicher exportieren", "description": "tooltip" diff --git a/src/_locales/el/messages.json b/src/_locales/el/messages.json index ea6a4a6662fe9..aefa2c6a580ad 100644 --- a/src/_locales/el/messages.json +++ b/src/_locales/el/messages.json @@ -40,7 +40,7 @@ "description": "appears as tab name in dashboard" }, "whitelistPageName": { - "message": "Έμπιστες τοποθεσίες", + "message": "Αξιόπιστοι ιστότοποι", "description": "appears as tab name in dashboard" }, "shortcutsPageName": { @@ -184,7 +184,7 @@ "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": { @@ -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": { @@ -224,7 +224,7 @@ "description": "Tooltip when hovering the top-most cell of the local-rules column." }, "popupTipSaveRules": { - "message": "Πατήστε για να κάνετε τις αλλαγές σας μόνιμες.", + "message": "Κάντε κλικ για να μονιμοποιήσετε τις αλλαγές σας.", "description": "Tooltip when hovering over the padlock in the dynamic filtering pane." }, "popupTipRevertRules": { @@ -1011,6 +1011,10 @@ "message": "Ανοίγει ανεπιθύμητες καρτέλες ή παράθυρα", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Οδηγεί σε κακόβουλο λογισμικό, ηλεκτρονικό «ψάρεμα»", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Επισημάνετε την ιστοσελίδα ως “NSFW” (“Not Safe For Work”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Συνέχεια", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Η αποκλεισμένη σελίδα θέλει να κάνει ανακατεύθυνση σε άλλο ιστότοπο. Αν επιλέξετε να συνεχίσετε, θα μεταβείτε απευθείας στο: {{url}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Εξαγωγή στο cloud storage", "description": "tooltip" diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 92fb26065ab9d..de0a8af1500eb 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -1012,6 +1012,10 @@ "message": "Opens unwanted tabs or windows", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "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”)", "description": "A checkbox to use for NSFW sites" @@ -1189,6 +1193,10 @@ "message": "Proceed", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff --git a/src/_locales/en_GB/messages.json b/src/_locales/en_GB/messages.json index 8fd9b46001abc..4b56a88ab99c9 100644 --- a/src/_locales/en_GB/messages.json +++ b/src/_locales/en_GB/messages.json @@ -1011,6 +1011,10 @@ "message": "Opens unwanted tabs or windows", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "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”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Proceed", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff --git a/src/_locales/eo/messages.json b/src/_locales/eo/messages.json index 1d69a1fda396f..1f00db737c90e 100644 --- a/src/_locales/eo/messages.json +++ b/src/_locales/eo/messages.json @@ -484,11 +484,11 @@ "description": "Filter lists section name" }, "3pGroupSocial": { - "message": "Social widgets", + "message": "Socialaj fenestraĵoj", "description": "Filter lists section name" }, "3pGroupCookies": { - "message": "Cookie notices", + "message": "Avizoj de kuketoj", "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": "Ŝalti miajn proprajn filtrilojn", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { - "message": "Allow custom filters requiring trust", + "message": "Permesi proprajn filtrilojn, kiuj postulas fidon", "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { @@ -844,7 +844,7 @@ "description": "Logger setting: A sentence to describe the purpose of the settings below" }, "loggerSettingPerEntryMaxAge": { - "message": "Preserve entries from the last {{input}} minutes", + "message": "Konservi enigojn ekde la lastaj {{input}} minutoj", "description": "A logger setting" }, "loggerSettingPerTabMaxLoads": { @@ -1011,6 +1011,10 @@ "message": "Malfermas nedeziratajn langetojn aŭ fenestrojn", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Marki la paĝon kiel «nelabortaŭgan»", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Procedi", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Eksporti al nuba konservado", "description": "tooltip" diff --git a/src/_locales/es/messages.json b/src/_locales/es/messages.json index 55bd2e95821f5..a4a418d0b45fc 100644 --- a/src/_locales/es/messages.json +++ b/src/_locales/es/messages.json @@ -1004,13 +1004,17 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "Se rompe cuando uBlock Origin está habilitado", + "message": "Funciona mal cuando uBlock Origin está habilitado", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { "message": "Abre pestañas o ventanas no deseadas", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Conduce a malware y phishing", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Etiquetar la página web como “NSFW” (“no es seguro/apropiado para el trabajo”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Continuar", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Exportar datos a la nube", "description": "tooltip" diff --git a/src/_locales/et/messages.json b/src/_locales/et/messages.json index 5ab8cc917fa23..0829551848ef9 100644 --- a/src/_locales/et/messages.json +++ b/src/_locales/et/messages.json @@ -1011,6 +1011,10 @@ "message": "Avab soovimatuid kaarte või aknaid", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Põhjustab pahavara, õngitsuskirju", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Sildista veebileht kui „NSFW“ (“tööks sobimatu”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Jätka", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Tõkestatud veebileht üritab suunata muule veebilehele. Jätkates suunatakse teid veebilehele {{url}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Ekspordi pilvehoidlasse", "description": "tooltip" diff --git a/src/_locales/eu/messages.json b/src/_locales/eu/messages.json index b87b777e765fc..c99740bb9436d 100644 --- a/src/_locales/eu/messages.json +++ b/src/_locales/eu/messages.json @@ -540,7 +540,7 @@ "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { - "message": "Enable my custom filters", + "message": "Aktibatu nire filtro pertsonalitsatuak", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { @@ -1011,6 +1011,10 @@ "message": "Ireki nahi ez diren erlaitzak edo leihoak", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Web orria «NSFW» moduan jarri (“Not Safe For Work” )", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Aurrera", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Esportatu hodei biltegiratzera", "description": "tooltip" diff --git a/src/_locales/fa/messages.json b/src/_locales/fa/messages.json index ef05c734625d9..654dead392add 100644 --- a/src/_locales/fa/messages.json +++ b/src/_locales/fa/messages.json @@ -484,7 +484,7 @@ "description": "Filter lists section name" }, "3pGroupSocial": { - "message": "Social widgets", + "message": "ابزارک‌های اجتماعی", "description": "Filter lists section name" }, "3pGroupCookies": { @@ -856,7 +856,7 @@ "description": "A logger setting" }, "loggerSettingPerEntryLineCount": { - "message": "Use {{input}} lines per entry in vertically expanded mode", + "message": "استفاده از {{input}} خط برای هر ورودی در حالت عمودی گسترش‌یافته", "description": "A logger setting" }, "loggerSettingHideColumnsPrompt": { @@ -928,7 +928,7 @@ "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": { @@ -936,7 +936,7 @@ "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,7 +944,7 @@ "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": { @@ -972,7 +972,7 @@ "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": { @@ -992,7 +992,7 @@ "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": { @@ -1011,6 +1011,10 @@ "message": "تب یا پنجره‌ی ناخواسته باز می‌کند", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "منجر به بدافزار یا فیشینگ می‌شود", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "علامت زدن صفحه به عنوان \"NSFW\" (\"نامناسب برای کار\")", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "صدور به فضای ذخیره سازی ابری", "description": "tooltip" @@ -1260,7 +1268,7 @@ "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": { @@ -1296,7 +1304,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 --git a/src/_locales/fi/messages.json b/src/_locales/fi/messages.json index da52acf6d3516..dbdc0638b3e7f 100644 --- a/src/_locales/fi/messages.json +++ b/src/_locales/fi/messages.json @@ -540,11 +540,11 @@ "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { - "message": "Ota omat suodattimet käyttöön", + "message": "Käytä omia suodattimia", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { - "message": "Allow custom filters requiring trust", + "message": "Salli luottamusta edellyttävät omat suodattimet", "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { @@ -928,7 +928,7 @@ "description": "Header of 'Filter issues' section in Support pane" }, "supportS3P1": { - "message": "Ilmoita ongelmista suodatuksessa tietyillä sivustoilla uBlockOrigin/uAssets-ongelmaseurannassa. Vaatii GitHub-tilin.", + "message": "Ilmoita sivustokohtaisista suodatinongelmista uBlockOrigin/uAssets -ongelmaseurantaan. Vaatii GitHub-tilin.", "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { @@ -1004,13 +1004,17 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "Hajoaa, kun uBlock Origin on käytössä", + "message": "Ei toimi oikein uBlock Originin ollessa käytössä", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { "message": "Avaa ei-toivottuja välilehtiä tai ikkunoita", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Johtaa badwareen ja tietojenkalasteluun", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Luokittele verkkosivu ns. työpaikalle sopimattomaksi, \"NSFW\" (\"Not Safe For Work\")", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Jatka", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Estetty sivu ohjautuu eri sivustolle. Jos jatkat, siirryt suoraan osoitteeseen {{url}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Vie pilvitallennustilaan", "description": "tooltip" diff --git a/src/_locales/fil/messages.json b/src/_locales/fil/messages.json index d38e062021d63..cc8937f5ead86 100644 --- a/src/_locales/fil/messages.json +++ b/src/_locales/fil/messages.json @@ -1011,6 +1011,10 @@ "message": "Kung anu-anong mga tab o window ang binubuksan", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Markahan bilang hindi dapat tinitignan sa pook-trabahuan (“Not Safe For Work”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Tumuloy", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "I-export sa imbakan sa cloud", "description": "tooltip" diff --git a/src/_locales/fr/messages.json b/src/_locales/fr/messages.json index fda258990d51f..309bba8600080 100644 --- a/src/_locales/fr/messages.json +++ b/src/_locales/fr/messages.json @@ -1011,6 +1011,10 @@ "message": "ouvre des onglets ou fenêtres indésirables", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "conduit à/redirige vers des logiciels malveillants, du hameçonnage", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Marquer le site Web en tant que \"NSFW\" (\"Not Safe For Work\", c'est-à-dire pour public averti/inapproprié au travail)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Poursuivre", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Exporter vers le stockage dans le nuage", "description": "tooltip" diff --git a/src/_locales/fy/messages.json b/src/_locales/fy/messages.json index ef97ec15d4891..3c21e63033e23 100644 --- a/src/_locales/fy/messages.json +++ b/src/_locales/fy/messages.json @@ -1011,6 +1011,10 @@ "message": "Iepenet net-winske ljepblêden of finsters", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Liedt ta badware, phishing", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "De webside labelje as ‘NSFW’ (‘Not Safe For Work’)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Trochgean", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Eksportearje nei cloudûnthâld", "description": "tooltip" diff --git a/src/_locales/gl/messages.json b/src/_locales/gl/messages.json index 291dc091324a8..e1104c0ebe33f 100644 --- a/src/_locales/gl/messages.json +++ b/src/_locales/gl/messages.json @@ -12,7 +12,7 @@ "description": "English: uBlock₀ — Dashboard" }, "dashboardUnsavedWarning": { - "message": "Aviso! ten cambios sen gardar", + "message": "Aviso! Non gardaches os cambios", "description": "A warning in the dashboard when navigating away from unsaved changes" }, "dashboardUnsavedWarningStay": { @@ -40,7 +40,7 @@ "description": "appears as tab name in dashboard" }, "whitelistPageName": { - "message": "Lista branca", + "message": "Sitios de confianza", "description": "appears as tab name in dashboard" }, "shortcutsPageName": { @@ -336,7 +336,7 @@ "description": "English: Color-blind friendly" }, "settingsAppearance": { - "message": "Aspecto", + "message": "Aparencia", "description": "Section for controlling user interface appearance" }, "settingsThemeLabel": { @@ -480,7 +480,7 @@ "description": "Filter lists section name" }, "3pGroupMalware": { - "message": "Dominios de malware", + "message": "Protección contra malware, seguridade", "description": "Filter lists section name" }, "3pGroupSocial": { @@ -596,7 +596,7 @@ "description": "" }, "rulesExport": { - "message": "Exportar a un arquivo…", + "message": "Exportar a un ficheiro…", "description": "Button in the 'My rules' pane" }, "rulesDefaultFileName": { @@ -632,15 +632,15 @@ "description": "A concise description of the 'Trusted sites' pane." }, "whitelistImport": { - "message": "Importar e anexar", + "message": "Importar e engadir…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { - "message": "Exportar", + "message": "Exportar…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExportFilename": { - "message": "o-meu-ublock-lista-branca_{{datetime}}.txt", + "message": "o-meu-ublock-webs-confiables_{{datetime}}.txt", "description": "The default filename to use for import/export purpose" }, "whitelistApply": { @@ -1011,6 +1011,10 @@ "message": "Abre ventás ou páxinas non desexadas", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leva a software malicioso, phishing", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Etiqueta a páxina como \"NSFW\" (\"Non é Segura No Traballo\")", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Proceder", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Exportar ó almacenamento na nube", "description": "tooltip" diff --git a/src/_locales/gu/messages.json b/src/_locales/gu/messages.json index 9db2f73145056..ef8377fd70c8f 100644 --- a/src/_locales/gu/messages.json +++ b/src/_locales/gu/messages.json @@ -1011,6 +1011,10 @@ "message": "Opens unwanted tabs or windows", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "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”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Proceed", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff --git a/src/_locales/he/messages.json b/src/_locales/he/messages.json index b036e932ece77..ca9073ecb951b 100644 --- a/src/_locales/he/messages.json +++ b/src/_locales/he/messages.json @@ -1011,6 +1011,10 @@ "message": "נפתחים לשוניות או חלונות לא רצויים", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "מוביל לנוזקה, פישינג", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "תיוג דף האינטרנט כ- לב\"ל ('לא בטוח לעבודה')", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "המשך", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "הדף החסום מבקש לעבור לאתר אחר. אם תחליטו להמשיך, תעברו ישירות ל: {{url}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "ייצא לאחסון ענן", "description": "tooltip" diff --git a/src/_locales/hi/messages.json b/src/_locales/hi/messages.json index 4e2cf86c5182b..34b7c17617134 100644 --- a/src/_locales/hi/messages.json +++ b/src/_locales/hi/messages.json @@ -1011,6 +1011,10 @@ "message": "अवांछित टैब या विंडो खोलता है", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "बैडवेयर, फ़िशिंग की ओर ले जाता है", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "वेब पेज को इस रूप में लेबल करें “NSFW” (“काम करने के लिए सुरक्षित नहीं”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "क्लाउड स्टोरेज में भेजें", "description": "tooltip" diff --git a/src/_locales/hr/messages.json b/src/_locales/hr/messages.json index bb5ed413611fd..68e37c5dd8eb2 100644 --- a/src/_locales/hr/messages.json +++ b/src/_locales/hr/messages.json @@ -1011,6 +1011,10 @@ "message": "Otvara neželjene kartice ili prozore", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Vodi do zloćudnog softvera, krađe identiteta", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Označite web stranicu kao “NSFW” (“nije sigurno za pregledavanje na poslu“)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Nastavi", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Izvezi u pohranu u oblaku", "description": "tooltip" diff --git a/src/_locales/hu/messages.json b/src/_locales/hu/messages.json index b41a850395026..472701531c979 100644 --- a/src/_locales/hu/messages.json +++ b/src/_locales/hu/messages.json @@ -12,7 +12,7 @@ "description": "English: uBlock₀ — Dashboard" }, "dashboardUnsavedWarning": { - "message": "Figyelem! Neked még vannak nem mentett változtatásaid", + "message": "Figyelem! Mentetlen változtatásai vannak.", "description": "A warning in the dashboard when navigating away from unsaved changes" }, "dashboardUnsavedWarningStay": { @@ -76,7 +76,7 @@ "description": "Message to be read by screen readers" }, "popupPowerSwitchInfo2": { - "message": "Kattints az uBlock₀ engedélyezéséhez ezen a webhelyen.", + "message": "Kattintson a uBlock₀ engedélyezéséhez ezen a webhelyen.", "description": "Message to be read by screen readers" }, "popupBlockedRequestPrompt": { @@ -108,7 +108,7 @@ "description": "For the new mobile-friendly popup design" }, "popupDomainsConnected_v2": { - "message": "Csatlakoztatott domain-ek", + "message": "Kapcsolódott domainek", "description": "For the new mobile-friendly popup design" }, "popupTipDashboard": { @@ -136,7 +136,7 @@ "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoPopups1": { - "message": "Kattints az összes előugró ablak letiltásához ezen a webhelyen", + "message": "Kattintson az összes felugró ablak letiltásához ezen a webhelyen", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoPopups2": { @@ -200,7 +200,7 @@ "description": "Caption for the no-cosmetic-filtering per-site switch" }, "popupNoRemoteFonts_v2": { - "message": "Távoli betűtípusok", + "message": "Távoli betűkészletek", "description": "Caption for the no-remote-fonts per-site switch" }, "popupNoScripting_v2": { @@ -276,7 +276,7 @@ "description": "Example of use: Version 1.26.4" }, "popup3pScriptFilter": { - "message": "szkript", + "message": "parancsfájl", "description": "Appears as an option to filter out firewall rows" }, "popup3pFrameFilter": { @@ -312,7 +312,7 @@ "description": "English: Click, Ctrl-click" }, "pickerContextMenuEntry": { - "message": "Elem blokkolása", + "message": "Elem blokkolása…", "description": "An entry in the browser's contextual menu" }, "settingsCollapseBlockedPrompt": { @@ -344,7 +344,7 @@ "description": "Label for checkbox to enable a custom dark theme" }, "settingsThemeAccent0Label": { - "message": "Egyedi akcentus szín", + "message": "Egyéni kiemelőszín", "description": "Label for checkbox to pick an accent color" }, "settingsCloudStorageEnabledPrompt": { @@ -400,11 +400,11 @@ "description": "background information: https://github.com/uBlockOrigin/uBlock-issues/issues/1513" }, "settingsAdvanced": { - "message": "Haladó", + "message": "Speciális", "description": "Section for controlling advanced-user settings" }, "settingsAdvancedSynopsis": { - "message": "Funkciók csak haladó felhasználóknak ", + "message": "Funkciók csak hozzáértő felhasználóknak", "description": "Description of section controlling advanced-user settings" }, "settingsAdvancedUserSettings": { @@ -444,7 +444,7 @@ "description": "English: Parse and enforce Adblock+ element hiding filters." }, "3pParseAllABPHideFiltersInfo": { - "message": "

Ez a beállítás engedélyezi az Adblock Plus-típusú “elemelrejtő” szűrőket. Ezek kizárólag kozmetikai célokat szolgálnak; elrejtik egy webhely azon elemeit, amelyek vizuálisan zavaróak, de a hálózati lekérések alapján nem szűrhetők ki.

A beállítás engedélyezése megnöveli a uBlock₀ memóriahasználatát.

", + "message": "A kozmetikai célú szűrők elrejtik a webhely azon elemeit, amelyek vizuálisan zavaróak, de a hálózati kérések alapján nem szűrhetők ki.", "description": "Describes the purpose of the 'Parse and enforce cosmetic filters' feature." }, "3pIgnoreGenericCosmeticFilters": { @@ -484,7 +484,7 @@ "description": "Filter lists section name" }, "3pGroupSocial": { - "message": "Közösségi widgetek", + "message": "Közösségi média felületi elemei", "description": "Filter lists section name" }, "3pGroupCookies": { @@ -536,15 +536,15 @@ "description": "used as a tooltip for error icon beside a list" }, "1pTrustWarning": { - "message": "Ne adj hozzá szűrőket megbízhatatlan forrásokból.", + "message": "Ne adjon hozzá megbízhatatlan forrásokból származó szűrőket.", "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { - "message": "Egyedi szűrőim engedélyezése", + "message": "Egyéni szűrők engedélyezése", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { - "message": "Megbízhatóságot igénylő egyéni szűrők engedélyezése", + "message": "Bizalmas egyéni szűrők engedélyezése", "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { @@ -640,7 +640,7 @@ "description": "Button in the 'Trusted sites' pane" }, "whitelistExportFilename": { - "message": "ublock-feherlistam_{{datetime}}.txt", + "message": "ublock-megbizhato-oldalak_{{datetime}}.txt", "description": "The default filename to use for import/export purpose" }, "whitelistApply": { @@ -704,7 +704,7 @@ "description": "Tooltip for the play button in the logger page" }, "loggerRowFiltererButtonTip": { - "message": "Naplózó szűrőjének kapcsolása", + "message": "Naplózó szűrése be/ki", "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": "Naplózó szűrő beállítások", + "message": "Naplózó szűrőbeállításai", "description": "Tooltip for the button to bring up logger output filtering options" }, "loggerRowFiltererBuiltinNot": { @@ -732,7 +732,7 @@ "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltinModified": { - "message": "módosított", + "message": "módosítva", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltin1p": { @@ -752,7 +752,7 @@ "description": "Label to identify a filter field" }, "loggerEntryDetailsFilterList": { - "message": "Szűrő lista", + "message": "Szűrőlista", "description": "Label to identify a filter list field" }, "loggerEntryDetailsRule": { @@ -760,15 +760,15 @@ "description": "Label to identify a rule field" }, "loggerEntryDetailsContext": { - "message": "Kontextus", + "message": "Környezet", "description": "Label to identify a context field (typically a hostname)" }, "loggerEntryDetailsRootContext": { - "message": "Gyökér kontextus", + "message": "Gyökérkörnyezet", "description": "Label to identify a root context field (typically a hostname)" }, "loggerEntryDetailsPartyness": { - "message": "Partyness", + "message": "Fél", "description": "Label to identify a field providing partyness information" }, "loggerEntryDetailsType": { @@ -780,7 +780,7 @@ "description": "Label to identify the URL of an entry" }, "loggerURLFilteringHeader": { - "message": "Dinamikus URL szűrő", + "message": "Webcímszabály", "description": "Small header to identify the dynamic URL filtering section" }, "loggerURLFilteringContextLabel": { @@ -792,7 +792,7 @@ "description": "Label for the type selector" }, "loggerStaticFilteringHeader": { - "message": "Statikus szűrés", + "message": "Statikus szűrő", "description": "Small header to identify the static filtering section" }, "loggerStaticFilteringSentence": { @@ -840,23 +840,23 @@ "description": "Message to show when a filter cannot be found in any filter lists" }, "loggerSettingDiscardPrompt": { - "message": "A naplózó bejegyzések, amelyek nem felelnek meg az alábbi három feltételnek, automatikusan eldobásra kerülnek:", + "message": "Azok a naplóbejegyzések, amelyek nem felelnek meg az alábbi három feltételnek, automatikusan eldobásra kerülnek:", "description": "Logger setting: A sentence to describe the purpose of the settings below" }, "loggerSettingPerEntryMaxAge": { - "message": "A bejegyzések megőrzése az utolsó {{input}} percből", + "message": "Bejegyzések megőrzése az utolsó {{input}} percből", "description": "A logger setting" }, "loggerSettingPerTabMaxLoads": { - "message": "Tartsa meg a legtöbb {{input}} lapot betöltéskor laponként", + "message": "Laponként legfeljebb {{input}} oldalbetöltés megtartása", "description": "A logger setting" }, "loggerSettingPerTabMaxEntries": { - "message": "Tartsa meg a legtöbb {{input}} bejegyzést laponként", + "message": "Laponként legfeljebb {{input}} bejegyzés megtartása", "description": "A logger setting" }, "loggerSettingPerEntryLineCount": { - "message": "Használja a {{input}} sorokat egy bejegyzésre függőlegesen bővített módban", + "message": "Bejegyzésenként {{input}} sor használata a függőlegesen bővített módban", "description": "A logger setting" }, "loggerSettingHideColumnsPrompt": { @@ -872,11 +872,11 @@ "description": "A label for the filter or rule column" }, "loggerSettingHideColumnContext": { - "message": "{{input}} Kontextus", + "message": "{{input}} Környezet", "description": "A label for the context column" }, "loggerSettingHideColumnPartyness": { - "message": "{{input}} Partyness", + "message": "{{input}} Fél", "description": "A label for the partyness column" }, "loggerExportFormatList": { @@ -888,7 +888,7 @@ "description": "Label for radio-button to pick export format" }, "loggerExportEncodePlain": { - "message": "Sík", + "message": "Egyszerű", "description": "Label for radio-button to pick export text format" }, "loggerExportEncodeMarkdown": { @@ -912,7 +912,7 @@ "description": "Header of 'Documentation' section in Support pane" }, "supportS1P1": { - "message": "Az uBlock Origin további funkcióihoz látogassa meg a dokumentációt itt: uBlock/wiki.", + "message": "A uBlock Origin további funkcióihoz olvassa el a dokumentációt itt: uBlock/wiki.", "description": "First paragraph of 'Documentation' section in Support pane" }, "supportS2H": { @@ -928,15 +928,15 @@ "description": "Header of 'Filter issues' section in Support pane" }, "supportS3P1": { - "message": "Adott weboldalra vonatkozó szűrőhibákat jelentse a uBlockOrigin/uAssets hibakövetőn. GitHub-fiók szükséges.", + "message": "Az adott weboldalra vonatkozó szűrőhibákat jelentse a uBlockOrigin/uAssets hibakövetőben. GitHub-fiók szükséges.", "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { - "message": "Fontos: Ne használjon hasonló célú reklámblokkolókat az uBlock Originnal egyszerre, mert ez szűrőhibákat okozhat bizonyos weboldalakon.", + "message": "Fontos: Ne használjon hasonló célú reklámblokkolókat a uBlock Originnel egyidőben, mert ez szűrőhibákat okozhat bizonyos weboldalakon.", "description": "Second paragraph of 'Filter issues' section in Support pane" }, "supportS3P3": { - "message": "Tippek: Bizonyosodjon meg arról, hogy a legfrissebb szűrőlistákat használja. A napló a legfontosabb eszköz a szűrőkkel kapcsolatos hibák diagnózisában.", + "message": "Tippek: Bizonyosodjon meg arról, hogy a legfrissebb szűrőlistákat használja. A naplózó a legfontosabb eszköz a szűrőkkel kapcsolatos hibák megállapításában.", "description": "Third paragraph of 'Filter issues' section in Support pane" }, "supportS4H": { @@ -944,19 +944,19 @@ "description": "Header of 'Bug report' section in Support pane" }, "supportS4P1": { - "message": "Az uBlock Origin hibáit jelentse a uBlockOrigin/uBlock-issue hibakövetőn. GitHub-fiók szükséges.", + "message": "A uBlock Origin hibáit jelentse a uBlockOrigin/uBlock-issue hibakövetőben. GitHub-fiók szükséges.", "description": "First paragraph of 'Bug report' section in Support pane" }, "supportS5H": { - "message": "Hibakeresési információ", + "message": "Hibakeresési információk", "description": "Header of 'Troubleshooting Information' section in Support pane" }, "supportS5P1": { - "message": "Az alább található technikai információk segíthetnek önkénteseinknek megoldani a problémáját.", + "message": "Az alábbi műszaki információk segíthetnek önkénteseinknek megoldani a problémáját.", "description": "First paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS5P2": { - "message": "Fontos: Az esetlegesen személyes vagy érzékeny adatok alapértelmezésből rejtve vannak. Az elrejtett információk megnehezíthetik a probléma megoldását.", + "message": "Fontos: Az esetleges személyes vagy érzékeny adatok alapértelmezés szerint eltávolításra kerülnek. A hiányzó információk megnehezíthetik a probléma megoldását.", "description": "Second paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS6H": { @@ -968,7 +968,7 @@ "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { - "message": "A szűrőlisták naponta frissülnek. Ügyeljen arra, hogy az Ön problémája ne szerepeljen már a legfrissebb szűrőlistákon.", + "message": "A szűrőlisták naponta frissülnek. Győződjön meg róla, hogy a problémáját nem oldják meg a legfrissebb szűrőlisták.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S2": { @@ -976,19 +976,19 @@ "description": "A paragraph in the filter issue reporter section" }, "supportS6URL": { - "message": "A weboldal címe:", + "message": "A weboldal címe:", "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "A weboldal...", + "message": "A weboldal…", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { - "message": "-- Válasszon egy opciót --", + "message": "-- Válasszon egy bejegyzést --", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { - "message": "Hirdetéseket vagy hirdetés maradványokat jelenít meg", + "message": "Hirdetéseket vagy azok maradványait jelenít meg", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { @@ -996,7 +996,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { - "message": "Érzékeli a uBlock Origin-t", + "message": "Észleli a uBlock Origint", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { @@ -1004,13 +1004,17 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "Hibásan működik, amikor az uBlock Origin be van kapcsolva", + "message": "Hibásan működik, amikor a uBlock Origin be van kapcsolva", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { "message": "Kéretlen lapokat vagy ablakokat nyit meg", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Kártékony programokhoz, adathalászathoz vezet", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "A weboldal megjelölése felnőtt tartalomként", "description": "A checkbox to use for NSFW sites" @@ -1024,7 +1028,7 @@ "description": "Text for 'Unredact' button" }, "aboutPrivacyPolicy": { - "message": "Adatvédelmi szabályzat", + "message": "Adatvédelmi irányelvek", "description": "Link to privacy policy on GitHub (English)" }, "aboutChangelog": { @@ -1048,7 +1052,7 @@ "description": "Link text to translations repo" }, "aboutFilterLists": { - "message": "Szűrő listák", + "message": "Szűrőlisták", "description": "Link text to uBO's own filter lists repo" }, "aboutDependencies": { @@ -1056,15 +1060,15 @@ "description": "Shown in the About pane" }, "aboutCDNs": { - "message": "Az uBO saját szűrőlistáit a következő ingyenes CDN-ek (angol) szolgáltatják:", + "message": "A uBO saját szűrőlistáit a következő ingyenes CDN-ek (angol) szolgáltatják:", "description": "Shown in the About pane" }, "aboutCDNsInfo": { - "message": "A szűrőlisták frissítéséhez egy véletlenszerűen kiválasztott CDN-t használ a bővítmény", + "message": "A szűrőlisták frissítéséhez egy véletlenszerűen kiválasztott CDN használatos.", "description": "Shown in the About pane" }, "aboutBackupDataButton": { - "message": "Biztonsági mentés fájlba", + "message": "Biztonsági mentés fájlba…", "description": "Text for button to create a backup of all settings" }, "aboutBackupFilename": { @@ -1076,7 +1080,7 @@ "description": "English: Restore from file..." }, "aboutResetDataButton": { - "message": "Alapértelmezett beállítások visszaállítása...", + "message": "Alapértelmezett beállítások visszaállítása…", "description": "English: Reset to default settings..." }, "aboutRestoreDataConfirm": { @@ -1096,7 +1100,7 @@ "description": "English: Network error: {{msg}}" }, "subscriberConfirm": { - "message": "uBlock₀: Hozzáadja a következő URL-t a saját szűrő listákhoz?\n\nNév: \"{{title}}\"\nURL: \"{{url}}\"", + "message": "Hozzáadja a következő webcímet a saját szűrőlistáihoz?\n\nNév: „{{title}}”\nWebcím: {{url}}", "description": "No longer used" }, "subscribeButton": { @@ -1187,6 +1191,10 @@ "message": "Továbblépés", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Exportálás a felhőszolgáltatásba", "description": "tooltip" @@ -1228,11 +1236,11 @@ "description": "" }, "contextMenuBlockElementInFrame": { - "message": "Elem blokkolása a keretben", + "message": "Elem blokkolása a keretben…", "description": "An entry in the browser's contextual menu" }, "contextMenuSubscribeToList": { - "message": "Feliratkozás szűrőlistára...", + "message": "Feliratkozás szűrőlistára…", "description": "An entry in the browser's contextual menu" }, "contextMenuTemporarilyAllowLargeMediaElements": { @@ -1248,7 +1256,7 @@ "description": "Placeholder string for input field used to capture a keyboard shortcut" }, "genericMergeViewScrollLock": { - "message": "Zárolt görgetés kapcsolása", + "message": "Zárolt görgetés be/ki", "description": "Tooltip for the button used to lock scrolling between the views in the 'My rules' pane" }, "genericCopyToClipboard": { @@ -1256,7 +1264,7 @@ "description": "Label for buttons used to copy something to the clipboard" }, "genericSelectAll": { - "message": "Mindent kijelöl", + "message": "Összes kijelölése", "description": "Label for buttons used to select all text in editor" }, "toggleCosmeticFiltering": { @@ -1264,19 +1272,19 @@ "description": "Label for keyboard shortcut used to toggle cosmetic filtering" }, "toggleJavascript": { - "message": "Javascript ki/bekapcsolása", + "message": "Javascript be/ki", "description": "Label for keyboard shortcut used to toggle no-scripting switch" }, "relaxBlockingMode": { - "message": "Relaxáló blokkolási mód", + "message": "Blokkolási mód lazítása", "description": "Label for keyboard shortcut used to relax blocking mode" }, "storageUsed": { - "message": "Használt tárolás: {{value}} {{unit}}", + "message": "Használt tárhely: {{value}} {{unit}}", "description": " In Setting pane, renders as (example): Storage used: 13.2 MB" }, "KB": { - "message": "KB", + "message": "kB", "description": "short for 'kilobytes'" }, "MB": { @@ -1288,7 +1296,7 @@ "description": "short for 'gigabytes'" }, "clickToLoad": { - "message": "Kattints a betöltéshez", + "message": "Kattintson a betöltéshez", "description": "Message used in frame placeholders" }, "linterMainReport": { diff --git a/src/_locales/hy/messages.json b/src/_locales/hy/messages.json index bc6d4c20a1472..e76041419c9c7 100644 --- a/src/_locales/hy/messages.json +++ b/src/_locales/hy/messages.json @@ -1011,6 +1011,10 @@ "message": "Բացում է անցանկալի ներդիրները կամ լուսամուտները", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Նշել վեբ էջը որպես «NSFW» («Աշխատանքի համար անվտանգ չէ»)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Արտահանել առ ամպային պահեստ", "description": "tooltip" diff --git a/src/_locales/id/messages.json b/src/_locales/id/messages.json index 2ac75d90f607f..38616c1449587 100644 --- a/src/_locales/id/messages.json +++ b/src/_locales/id/messages.json @@ -128,7 +128,7 @@ "description": "Tooltip used for the logger icon in the panel" }, "popupTipReport": { - "message": "Laporkan masalah situs web ini", + "message": "Laporkan masalah di situs web ini", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipNoPopups": { @@ -536,7 +536,7 @@ "description": "used as a tooltip for error icon beside a list" }, "1pTrustWarning": { - "message": "Jangan tambah filter dari sumber yang tidak tepercaya.", + "message": "Jangan tambah filter dari sumber yang tidak terpercaya.", "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { @@ -1011,6 +1011,10 @@ "message": "Membuka tab atau jendela yang tidak diinginkan", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Mengarah ke perangkat lunak jahat, phishing", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Beri label halaman web sebagai “TAUSB” (“Tidak Aman Untuk Saat Bekerja”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Lanjutkan", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Ekspor ke penyimpanan awan", "description": "tooltip" diff --git a/src/_locales/it/messages.json b/src/_locales/it/messages.json index c87a90ff97181..fc7b8499500bc 100644 --- a/src/_locales/it/messages.json +++ b/src/_locales/it/messages.json @@ -380,7 +380,7 @@ "description": "" }, "settingsNoLargeMediaPrompt": { - "message": "Blocca elementi multimediali maggiori di {{input}} KB", + "message": "Blocca gli elementi multimediali di dimensioni maggiori di {{input}} KB", "description": "" }, "settingsNoRemoteFontsPrompt": { @@ -404,7 +404,7 @@ "description": "Section for controlling advanced-user settings" }, "settingsAdvancedSynopsis": { - "message": "Caratteristiche adatte solo ad utenti tecnici.", + "message": "Funzionalità adatte solo per gli utenti tecnici.", "description": "Description of section controlling advanced-user settings" }, "settingsAdvancedUserSettings": { @@ -440,11 +440,11 @@ "description": "A button in the in the _3rd-party filters_ pane" }, "3pParseAllABPHideFiltersPrompt1": { - "message": "Analizza e applica filtri cosmetici", + "message": "Analizza e applica i filtri cosmetici", "description": "English: Parse and enforce Adblock+ element hiding filters." }, "3pParseAllABPHideFiltersInfo": { - "message": "\nI filtri cosmetici servono a nascondere gli elementi in una pagina web che sono considerati un fastidio visivo, e che non possono essere bloccati dai motori di filtraggio basati sulla richiesta di rete.", + "message": "\nI filtri cosmetici servono a nascondere gli elementi in una pagina web che sono considerati visivamente fastidiosi e che non possono essere bloccati dai motori di filtraggio basati sulle richieste di rete.", "description": "Describes the purpose of the 'Parse and enforce cosmetic filters' feature." }, "3pIgnoreGenericCosmeticFilters": { @@ -456,7 +456,7 @@ "description": "Describes the purpose of the 'Ignore generic cosmetic filters' feature." }, "3pSuspendUntilListsAreLoaded": { - "message": "Sospendi l'attività di rete finché non vengono caricate tutte le liste filtri", + "message": "Sospendi l'attività di rete finché tutte le liste dei filtri sono caricate", "description": "A checkbox in the 'Filter lists' pane" }, "3pListsOfBlockedHostsHeader": { @@ -480,15 +480,15 @@ "description": "Filter lists section name" }, "3pGroupMalware": { - "message": "Domini con Malware", + "message": "Protezione dai malware, sicurezza", "description": "Filter lists section name" }, "3pGroupSocial": { - "message": "Widget sociali", + "message": "Widget dei social", "description": "Filter lists section name" }, "3pGroupCookies": { - "message": "Avviso sui cookie", + "message": "Avvisi sui cookie", "description": "Filter lists section name" }, "3pGroupAnnoyances": { @@ -512,7 +512,7 @@ "description": "The label for the checkbox used to import external filter lists" }, "3pExternalListsHint": { - "message": "Un URL per riga. URL non validi verranno silenziosamente ignorati.", + "message": "Un URL per riga. Gli URL non validi saranno silenziosamente ignorati.", "description": "Short information about how to use the textarea to import external filter lists by URL" }, "3pExternalListObsolete": { @@ -536,7 +536,7 @@ "description": "used as a tooltip for error icon beside a list" }, "1pTrustWarning": { - "message": "Non aggiungere filtri da fonti non attendibili.", + "message": "Non aggiungere filtri da fonti non affidabili.", "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { @@ -688,7 +688,7 @@ "description": "Tooltip for the popup panel button in the logger page" }, "loggerInfoTip": { - "message": "uBlock Origin Wiki: Registro", + "message": "Wiki di uBlock Origin: Il registro", "description": "Tooltip for the top-right info label in the logger page" }, "loggerClearTip": { @@ -836,7 +836,7 @@ "description": "Below this sentence, the filter list(s) in which the filter was found" }, "loggerStaticFilteringFinderSentence2": { - "message": "Non è stato possibile trovare il filtro statico in nessuno degli elenchi di filtri attualmente abilitati", + "message": "Non è stato possibile trovare il filtro statico in alcuna delle liste dei filtri attualmente abilitate", "description": "Message to show when a filter cannot be found in any filter lists" }, "loggerSettingDiscardPrompt": { @@ -932,7 +932,7 @@ "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { - "message": "Importante: Evita di utilizzare altre estensioni simili insieme a uBlock Origin, poiché ciò potrebbe causare problemi di filtro su specifici siti.", + "message": "Importante: Evita di utilizzare altre estensioni simili insieme a uBlock Origin, poiché ciò potrebbe causare problemi di filtraggio su specifici siti.", "description": "Second paragraph of 'Filter issues' section in Support pane" }, "supportS3P3": { @@ -952,7 +952,7 @@ "description": "Header of 'Troubleshooting Information' section in Support pane" }, "supportS5P1": { - "message": "Di seguito sono riportate le informazioni tecniche che potrebbero essere utili quando i volontari stanno cercando di aiutarti a risolvere un problema.", + "message": "Di seguito sono riportate informazioni tecniche che potrebbero essere utili quando i volontari cercheranno di aiutarti a risolvere un problema.", "description": "First paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS5P2": { @@ -1011,6 +1011,10 @@ "message": "Apre schede o finestre indesiderate", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Porta a badware, phishing", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Etichetta la pagina web come “NSFW” (“Not Safe For Work”)", "description": "A checkbox to use for NSFW sites" @@ -1024,11 +1028,11 @@ "description": "Text for 'Unredact' button" }, "aboutPrivacyPolicy": { - "message": "Codice di condotta sulla privacy", + "message": "Informativa sulla privacy", "description": "Link to privacy policy on GitHub (English)" }, "aboutChangelog": { - "message": "Changelog", + "message": "Registro delle modifiche", "description": "" }, "aboutCode": { @@ -1072,7 +1076,7 @@ "description": "English: my-ublock-backup_{{datetime}}.txt" }, "aboutRestoreDataButton": { - "message": "Ripristina configurazione", + "message": "Ripristina dal file...", "description": "English: Restore from file..." }, "aboutResetDataButton": { @@ -1168,7 +1172,7 @@ "description": "English: Close this window" }, "docblockedDontWarn": { - "message": "Non avvisarmi più per questo sito", + "message": "Non avvisarmi di nuovo riguardo questo sito", "description": "Label for checkbox in document-blocked page" }, "docblockedProceed": { @@ -1187,6 +1191,10 @@ "message": "Procedi", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Esporta nel cloud", "description": "tooltip" @@ -1240,7 +1248,7 @@ "description": "A context menu entry, present when large media elements have been blocked on the current site" }, "contextMenuViewSource": { - "message": "Visualizza origine...", + "message": "Visualizza il codice sorgente…", "description": "A context menu entry, to view the source code of the target resource" }, "shortcutCapturePlaceholder": { @@ -1260,7 +1268,7 @@ "description": "Label for buttons used to select all text in editor" }, "toggleCosmeticFiltering": { - "message": "Attiva/Disattiva filtri cosmetici", + "message": "Attiva/Disattiva il filtraggio cosmetico", "description": "Label for keyboard shortcut used to toggle cosmetic filtering" }, "toggleJavascript": { @@ -1296,7 +1304,7 @@ "description": "Summary of number of errors as reported by the linter " }, "unprocessedRequestTooltip": { - "message": "Non è stato possibile filtrare correttamente all'avvio del browser.\nRicaricare la pagina per garantire un filtraggio corretto", + "message": "Non è stato effettuato correttamente il filtraggio all'avvio del browser.\nRicarica la pagina per garantire un filtraggio adeguato.", "description": "A warning which will appear in the popup panel if needed" }, "dummy": { diff --git a/src/_locales/ja/messages.json b/src/_locales/ja/messages.json index add025fe64505..673909dfe8f7c 100644 --- a/src/_locales/ja/messages.json +++ b/src/_locales/ja/messages.json @@ -480,7 +480,7 @@ "description": "Filter lists section name" }, "3pGroupMalware": { - "message": "マルウェアドメイン", + "message": "マルウェアからの保護、セキュリティ", "description": "Filter lists section name" }, "3pGroupSocial": { @@ -540,7 +540,7 @@ "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": { @@ -1011,6 +1011,10 @@ "message": "勝手にタブやウィンドウを開きます", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "悪質ソフトやフィッシングへの誘導", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "ウェブページに“NSFW” (閲覧注意、“Not Safe For Work”) とラベルをつける", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "続行する", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "ブロックしたページは別のサイトへリダイレクトしようとしています。続行すると次の URL へ移動します: {{url}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "クラウドストレージにエクスポートします", "description": "tooltip" diff --git a/src/_locales/ka/messages.json b/src/_locales/ka/messages.json index da9ea635b7a7d..b95c3d428376d 100644 --- a/src/_locales/ka/messages.json +++ b/src/_locales/ka/messages.json @@ -1011,6 +1011,10 @@ "message": "ხსნის არასასურველ ჩანართებს ან ფანჯრებს", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "გადადის მავნე, თაღლითურ შიგთავსზე", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "გვერდი მოინიშნოს, როგორც „NSFW“ („შეუსაბამო“)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "მაინც გადასვლა", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "ეს შეზღუდული გვერდი ცდილობს სხვა საიტზე გადაყვანას. თუ განაგრძობთ, პირდაპირ გაიხსნება: {{url}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "ღრუბლოვან საცავში შენახვა", "description": "tooltip" diff --git a/src/_locales/kk/messages.json b/src/_locales/kk/messages.json index bd037e0a72ff5..a352345886b29 100644 --- a/src/_locales/kk/messages.json +++ b/src/_locales/kk/messages.json @@ -1011,6 +1011,10 @@ "message": "Opens unwanted tabs or windows", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "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”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Proceed", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Бұлтты жадқа экспорттау", "description": "tooltip" diff --git a/src/_locales/kn/messages.json b/src/_locales/kn/messages.json index 7ae8e6ff84e0a..84394e4656a4f 100644 --- a/src/_locales/kn/messages.json +++ b/src/_locales/kn/messages.json @@ -72,7 +72,7 @@ "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\nಈ ಪುಟದಲ್ಲಿ ಮಾತ್ರ uBlock₀ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು Ctrl+ಕ್ಲಿಕ್ ಮಾಡಿ.", "description": "Message to be read by screen readers" }, "popupPowerSwitchInfo2": { @@ -116,7 +116,7 @@ "description": "English: Click to open the dashboard" }, "popupTipZapper": { - "message": "Enter element zapper mode", + "message": "Element zapper ಮೋಡ್ ಅನ್ನು ಬಳಸಿ", "description": "Tooltip for the element-zapper icon in the popup panel" }, "popupTipPicker": { @@ -136,15 +136,15 @@ "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": { @@ -188,15 +188,15 @@ "description": "Tooltip for the no-scripting per-site switch" }, "popupNoPopups_v2": { - "message": "Pop-up windows", + "message": "ಪಾಪ್-ಅಪ್ ವಿಂಡೋ", "description": "Caption for the no-popups per-site switch" }, "popupNoLargeMedia_v2": { - "message": "Large media elements", + "message": "ದೊಡ್ಡ ಮಾಧ್ಯಮ ಅಂಶಗಳು", "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": { @@ -224,11 +224,11 @@ "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": { @@ -864,7 +864,7 @@ "description": "Logger settings: a sentence to describe the purpose of the checkboxes below" }, "loggerSettingHideColumnTime": { - "message": "{{input}} Time", + "message": "{{input}} ಗಂಟೆ", "description": "A label for the time column" }, "loggerSettingHideColumnFilter": { @@ -1011,6 +1011,10 @@ "message": "Opens unwanted tabs or windows", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "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”)", "description": "A checkbox to use for NSFW sites" @@ -1144,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": "uBlock Origin ಈ ಕೆಳಗಿನ ಪುಟವನ್ನು ಲೋಡ್ ಮಾಡುವುದನ್ನು ತಡೆಯುತ್ತದೆ:", "description": "Used in the strict-blocking page" }, "docblockedPrompt2": { @@ -1187,6 +1191,10 @@ "message": "Proceed", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" @@ -1272,7 +1280,7 @@ "description": "Label for keyboard shortcut used to relax blocking mode" }, "storageUsed": { - "message": "Storage used: {{value}} {{unit}}", + "message": "ಉಪಯೊಗಿಸುತಿರುವ ಸಂಗ್ರಹಣೆ: {{value}} {{unit}}", "description": " In Setting pane, renders as (example): Storage used: 13.2 MB" }, "KB": { diff --git a/src/_locales/ko/messages.json b/src/_locales/ko/messages.json index 486e54fc5ed76..c3cb5cea26b5f 100644 --- a/src/_locales/ko/messages.json +++ b/src/_locales/ko/messages.json @@ -1011,6 +1011,10 @@ "message": "원치 않는 탭이나 창을 엽니다", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "악성코드, 피싱으로 유도합니다", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "웹페이지를 \"NSFW\" (“Not Safe For Work”)로 분류", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "계속", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "차단된 페이지에서 다른 사이트로 이동하려 합니다. 계속하시면, {{url}} 주소로 바로 이동합니다.", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "클라우드 저장소로 내보내기", "description": "tooltip" diff --git a/src/_locales/lt/messages.json b/src/_locales/lt/messages.json index a44db57fe1420..263a9d8fe6e9a 100644 --- a/src/_locales/lt/messages.json +++ b/src/_locales/lt/messages.json @@ -940,7 +940,7 @@ "description": "Third paragraph of 'Filter issues' section in Support pane" }, "supportS4H": { - "message": "Bug report", + "message": "Klaidos pranešimas", "description": "Header of 'Bug report' section in Support pane" }, "supportS4P1": { @@ -1011,6 +1011,10 @@ "message": "Opens unwanted tabs or windows", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "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”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Tęsti", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Eksportuoti į nuotolinę saugyklą", "description": "tooltip" diff --git a/src/_locales/lv/messages.json b/src/_locales/lv/messages.json index c529a68246d4d..5135003bf11a5 100644 --- a/src/_locales/lv/messages.json +++ b/src/_locales/lv/messages.json @@ -340,7 +340,7 @@ "description": "Section for controlling user interface appearance" }, "settingsThemeLabel": { - "message": "Izskats", + "message": "Motīvs", "description": "Label for checkbox to enable a custom dark theme" }, "settingsThemeAccent0Label": { @@ -480,7 +480,7 @@ "description": "Filter lists section name" }, "3pGroupMalware": { - "message": "Ļaundabīgo programmu domēni", + "message": "Aizsardzība pret ļaunprātīgām (inficētas vai satur vīrusus) vietnēm, drošība", "description": "Filter lists section name" }, "3pGroupSocial": { @@ -552,7 +552,7 @@ "description": "Button in the 'My filters' pane" }, "1pExport": { - "message": "Eksportēt", + "message": "Eksportēt…", "description": "Button in the 'My filters' pane" }, "1pExportFilename": { @@ -636,7 +636,7 @@ "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { - "message": "Eksportēt", + "message": "Eksportēt…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExportFilename": { @@ -1011,6 +1011,10 @@ "message": "Atver nevēlamas cilnes vai logus", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Noved pie slitkas programmatūras, pikšķerēšanas", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Iezīmēt tīmekļa lapu kā \"NSFW\" (\"Not Safe for Work (nav droša darbam))", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Turpināt", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Eksports uz mākoņdatu glabātuvi", "description": "tooltip" diff --git a/src/_locales/mk/messages.json b/src/_locales/mk/messages.json index 0a7777f9b04aa..f0aca830ee686 100644 --- a/src/_locales/mk/messages.json +++ b/src/_locales/mk/messages.json @@ -56,11 +56,11 @@ "description": "appears as tab name in dashboard" }, "supportPageName": { - "message": "Support", + "message": "Поддршка", "description": "appears as tab name in dashboard" }, "assetViewerPageName": { - "message": "uBlock₀ — Asset viewer", + "message": "uBlock₀ — Прегледувач на средства", "description": "Title for the asset viewer page" }, "advancedSettingsPageName": { @@ -68,15 +68,15 @@ "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": "Кликнете: деактивирајте/активирајте uBlock₀ за оваа страница.\n\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": { - "message": "Click to enable uBlock₀ for this site.", + "message": "Кликнете за да го активирате uBlock₀ за оваа страница.", "description": "Message to be read by screen readers" }, "popupBlockedRequestPrompt": { @@ -128,11 +128,11 @@ "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": { - "message": "Toggle the blocking of all popups for this site", + "message": "Промени ја блокадата на сите поп-упи за оваа страница", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoPopups1": { @@ -140,23 +140,23 @@ "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": { @@ -168,15 +168,15 @@ "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": { @@ -276,11 +276,11 @@ "description": "Example of use: Version 1.26.4" }, "popup3pScriptFilter": { - "message": "script", + "message": "скрипта", "description": "Appears as an option to filter out firewall rows" }, "popup3pFrameFilter": { - "message": "frame", + "message": "рамка", "description": "Appears as an option to filter out firewall rows" }, "pickerCreate": { @@ -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": { @@ -328,7 +328,7 @@ "description": "A checkbox in the Settings pane" }, "settingsContextMenuPrompt": { - "message": "Make use of context menu where appropriate", + "message": "Искористете го контекстуалното мени каде што е соодветно", "description": "English: Make use of context menu where appropriate" }, "settingsColorBlindPrompt": { @@ -336,15 +336,15 @@ "description": "English: Color-blind friendly" }, "settingsAppearance": { - "message": "Appearance", + "message": "Изглед", "description": "Section for controlling user interface appearance" }, "settingsThemeLabel": { - "message": "Theme", + "message": "Тема", "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,15 +356,15 @@ "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": { - "message": "Disable hyperlink auditing", + "message": "Деактивирајте проверка на хиперврски", "description": "English: " }, "settingsWebRTCIPAddressHiddenPrompt": { - "message": "Prevent WebRTC from leaking local IP addresses", + "message": "Спречете WebRTC да ги открие локалните IP адреси", "description": "English: " }, "settingPerSiteSwitchGroup": { @@ -392,19 +392,19 @@ "description": "The default state for the per-site no-scripting switch" }, "settingsNoCSPReportsPrompt": { - "message": "Block CSP reports", + "message": "Блокирајте CSP извештаи", "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": { - "message": "Advanced", + "message": "Напредно", "description": "Section for controlling advanced-user settings" }, "settingsAdvancedSynopsis": { - "message": "Features suitable only for technical users", + "message": "Функции погодни само за технички корисници", "description": "Description of section controlling advanced-user settings" }, "settingsAdvancedUserSettings": { @@ -440,23 +440,23 @@ "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": "Генералистичките козметички филтри се оние козметички филтри што се наменети да се применуваат на сите веб-страници. Вклучувањето на оваа опција ќе ја елиминира оптовареноста на меморијата и ЦПУ-то додадена на веб-страниците како резултат на обработката на генералистичките козметички филтри.\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": { @@ -484,11 +484,11 @@ "description": "Filter lists section name" }, "3pGroupSocial": { - "message": "Social widgets", + "message": "Социјални widgets", "description": "Filter lists section name" }, "3pGroupCookies": { - "message": "Cookie notices", + "message": "Известија за колачиња", "description": "Filter lists section name" }, "3pGroupAnnoyances": { @@ -496,7 +496,7 @@ "description": "Filter lists section name" }, "3pGroupMultipurpose": { - "message": "Multipurpose", + "message": "Многуцелно", "description": "Filter lists section name" }, "3pGroupRegions": { @@ -504,7 +504,7 @@ "description": "Filter lists section name" }, "3pGroupCustom": { - "message": "Custom", + "message": "Прилагодено", "description": "Filter lists section name" }, "3pImport": { @@ -520,11 +520,11 @@ "description": "used as a tooltip for the out-of-date icon beside a list" }, "3pViewContent": { - "message": "view content", + "message": "прегледајте содржина", "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,19 +532,19 @@ "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": { @@ -560,7 +560,7 @@ "description": "English: my-ublock-static-filters_{{datetime}}.txt" }, "1pApplyChanges": { - "message": "Apply changes", + "message": "Применете ги промените", "description": "English: Apply changes" }, "rulesPermanentHeader": { @@ -608,7 +608,7 @@ "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": { @@ -628,7 +628,7 @@ "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": { @@ -676,19 +676,19 @@ "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 Origin вики: Логер", "description": "Tooltip for the top-right info label in the logger page" }, "loggerClearTip": { @@ -704,15 +704,15 @@ "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": { @@ -732,7 +732,7 @@ "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": { @@ -764,7 +764,7 @@ "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": { @@ -836,31 +836,31 @@ "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": { - "message": "Hide columns:", + "message": "Скријте колони:", "description": "Logger settings: a sentence to describe the purpose of the checkboxes below" }, "loggerSettingHideColumnTime": { @@ -896,123 +896,127 @@ "description": "Label for radio-button to pick export text format" }, "supportOpenButton": { - "message": "Open", + "message": "Отвори", "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Создај нова пријава", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Најди слични пријави", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { - "message": "Documentation", + "message": "Документација", "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 issue tracker. Потребен е 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": { - "message": "Bug report", + "message": "Пријава за грешка", "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 issue tracker. Потребен е 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": "За да се избегне оптоварување на волонтерите со дупликат пријави, ве молиме проверете дека проблемот веќе не е пријавен.", "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": { - "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": "Има преOverlayи или други непријатности", "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": "Води до злонамерен софтвер, фишинг", "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": { @@ -1024,7 +1028,7 @@ "description": "Text for 'Unredact' button" }, "aboutPrivacyPolicy": { - "message": "Privacy policy", + "message": "Политика на приватност", "description": "Link to privacy policy on GitHub (English)" }, "aboutChangelog": { @@ -1052,19 +1056,19 @@ "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 се одвиваат слободно на следните CDN-ови:", "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": { - "message": "Back up to file…", + "message": "Направи резервна копија во датотека…", "description": "Text for button to create a backup of all settings" }, "aboutBackupFilename": { @@ -1072,23 +1076,23 @@ "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": { @@ -1096,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": { @@ -1140,15 +1144,15 @@ "description": "Firefox-specific: appears as 'uBlock₀ (off)'" }, "docblockedTitle": { - "message": "Page blocked", + "message": "Страницата е блокирана", "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": { @@ -1168,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": { @@ -1184,19 +1188,23 @@ "description": "English: Permanently" }, "docblockedDisable": { - "message": "Proceed", + "message": "Продолжи", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Блокираната страница сака да ве пренасочи на друга веб-страница. Ако изберете да продолжите, директно ќе навигирате до: {{url}}", + "description": "Text warning about an incoming redirect" + }, "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": { @@ -1208,11 +1216,11 @@ "description": "used as a prompt for the user to provide a custom device name" }, "advancedSettingsWarning": { - "message": "Warning! Change these advanced settings at your own risk.", + "message": "Предупредување! Менувањето на овие напредни поставки е на ваша сопствена одговорност.", "description": "A warning to users at the top of 'Advanced settings' page" }, "genericSubmit": { - "message": "Submit", + "message": "Испрати", "description": "for generic 'Submit' buttons" }, "genericApplyChanges": { @@ -1228,19 +1236,19 @@ "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": { - "message": "View source code…", + "message": "Прикажи изворен код…", "description": "A context menu entry, to view the source code of the target resource" }, "shortcutCapturePlaceholder": { @@ -1248,7 +1256,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": { @@ -1256,15 +1264,15 @@ "description": "Label for buttons used to copy something to the clipboard" }, "genericSelectAll": { - "message": "Select all", + "message": "Избери сè", "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": { @@ -1272,7 +1280,7 @@ "description": "Label for keyboard shortcut used to relax blocking mode" }, "storageUsed": { - "message": "Место вземеноЧ {{value}} {{unit}}", + "message": "Место вземено: {{value}} {{unit}}", "description": " In Setting pane, renders as (example): Storage used: 13.2 MB" }, "KB": { @@ -1288,15 +1296,15 @@ "description": "short for 'gigabytes'" }, "clickToLoad": { - "message": "Click to load", + "message": "Кликнете за да вчитате", "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 --git a/src/_locales/ml/messages.json b/src/_locales/ml/messages.json index b4c1b3a162a36..1bb8d1e866f65 100644 --- a/src/_locales/ml/messages.json +++ b/src/_locales/ml/messages.json @@ -1011,6 +1011,10 @@ "message": "Opens unwanted tabs or windows", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "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”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Proceed", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "ക്ലൌഡ് സ്റ്റോറേജിലേക്ക് എക്സ്പോര്‍ട്ട്‌ ചെയ്യുക", "description": "tooltip" diff --git a/src/_locales/mr/messages.json b/src/_locales/mr/messages.json index 6530b322480be..56407af1acfa3 100644 --- a/src/_locales/mr/messages.json +++ b/src/_locales/mr/messages.json @@ -1011,6 +1011,10 @@ "message": "Opens unwanted tabs or windows", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "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”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Proceed", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff --git a/src/_locales/ms/messages.json b/src/_locales/ms/messages.json index ed5b060b45f94..de9b9cdee9c4d 100644 --- a/src/_locales/ms/messages.json +++ b/src/_locales/ms/messages.json @@ -8,7 +8,7 @@ "description": "this will be in the Chrome web store: must be 132 characters or less" }, "dashboardName": { - "message": "uBlock₀ — Papanmuka", + "message": "uBlock₀ — Papan pemuka", "description": "English: uBlock₀ — Dashboard" }, "dashboardUnsavedWarning": { @@ -124,7 +124,7 @@ "description": "English: Enter element picker mode" }, "popupTipLog": { - "message": "Membuka catatan", + "message": "Buka pengelog", "description": "Tooltip used for the logger icon in the panel" }, "popupTipReport": { @@ -188,7 +188,7 @@ "description": "Tooltip for the no-scripting per-site switch" }, "popupNoPopups_v2": { - "message": "Tetingkap pop timbul", + "message": "Tingkap timbul", "description": "Caption for the no-popups per-site switch" }, "popupNoLargeMedia_v2": { @@ -200,7 +200,7 @@ "description": "Caption for the no-cosmetic-filtering per-site switch" }, "popupNoRemoteFonts_v2": { - "message": "Fon terpencil", + "message": "Font tersendiri", "description": "Caption for the no-remote-fonts per-site switch" }, "popupNoScripting_v2": { @@ -484,11 +484,11 @@ "description": "Filter lists section name" }, "3pGroupSocial": { - "message": "Social widgets", + "message": "Widget sosial", "description": "Filter lists section name" }, "3pGroupCookies": { - "message": "Cookie notices", + "message": "Notis kuki", "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": "Dayakan penapis tersuai saya", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { - "message": "Allow custom filters requiring trust", + "message": "Benarkan penapis tersuai yang memerlukan kepercayaan", "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { @@ -1011,6 +1011,10 @@ "message": "Membuka tab atau tetingkap yang tidak diingini", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Labelkan laman web itu sebagai \"NSFW\" (“Not Safe For Work”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Teruskan", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Eksport ke storan awan", "description": "tooltip" @@ -1264,7 +1272,7 @@ "description": "Label for keyboard shortcut used to toggle cosmetic filtering" }, "toggleJavascript": { - "message": "Toggle JavaScript", + "message": "Togol JavaScript", "description": "Label for keyboard shortcut used to toggle no-scripting switch" }, "relaxBlockingMode": { diff --git a/src/_locales/nb/messages.json b/src/_locales/nb/messages.json index 6451d65426f51..912dbf4d127b6 100644 --- a/src/_locales/nb/messages.json +++ b/src/_locales/nb/messages.json @@ -484,11 +484,11 @@ "description": "Filter lists section name" }, "3pGroupSocial": { - "message": "Sosiale medie-widgeter", + "message": "Sosiale mediers moduler", "description": "Filter lists section name" }, "3pGroupCookies": { - "message": "Cookie meldinger", + "message": "Infokapselmeldinger", "description": "Filter lists section name" }, "3pGroupAnnoyances": { @@ -1011,6 +1011,10 @@ "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", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Merk nettsiden som “NSFW” (“Not Safe For Work”) (advarsel mot sider med upassende innhold)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Fortsett", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Eksporter til nettlagring", "description": "tooltip" diff --git a/src/_locales/nl/messages.json b/src/_locales/nl/messages.json index 554544ccb5437..e0ab0747789a4 100644 --- a/src/_locales/nl/messages.json +++ b/src/_locales/nl/messages.json @@ -1011,6 +1011,10 @@ "message": "Opent ongewenste tabbladen of vensters", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leidt tot badware, phishing", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "De webpagina labelen als ‘NSFW’ (‘Not Safe For Work’)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Doorgaan", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Exporteren naar cloudopslag", "description": "tooltip" diff --git a/src/_locales/oc/messages.json b/src/_locales/oc/messages.json index 6d141a65722d6..1b4b4c0d251de 100644 --- a/src/_locales/oc/messages.json +++ b/src/_locales/oc/messages.json @@ -1011,6 +1011,10 @@ "message": "Opens unwanted tabs or windows", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "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”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Contunhar", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff --git a/src/_locales/pa/messages.json b/src/_locales/pa/messages.json index b58a1203bc44b..570ef52205114 100644 --- a/src/_locales/pa/messages.json +++ b/src/_locales/pa/messages.json @@ -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": { @@ -540,7 +540,7 @@ "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": { @@ -920,7 +920,7 @@ "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": { @@ -1011,6 +1011,10 @@ "message": "ਬੇਲੋੜੀਆਂ ਟੈਬਾਂ ਜਾਂ ਵਿੰਡੋ ਖੋਲ੍ਹਦਾ ਹੈ", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "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”)", "description": "A checkbox to use for NSFW sites" @@ -1068,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": { @@ -1187,6 +1191,10 @@ "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "ਕਲਾਉਡ ਸਟੋਰੇਜ਼ ਉੱਤੇ ਐਕਸਪੋਰਟ ਕਰੋ", "description": "tooltip" diff --git a/src/_locales/pl/messages.json b/src/_locales/pl/messages.json index a4ce6344d7508..4599037658dce 100644 --- a/src/_locales/pl/messages.json +++ b/src/_locales/pl/messages.json @@ -1011,6 +1011,10 @@ "message": "Otwiera niepożądane karty lub okna", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Prowadzi do szkodliwego oprogramowania, phishingu", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Oznacz stronę internetową jako „NSFW” („Not Safe For Work (nieodpowiednią w pracy)”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Kontynuuj", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Eksportuj do chmury", "description": "tooltip" diff --git a/src/_locales/pt_BR/messages.json b/src/_locales/pt_BR/messages.json index 1704ab211707c..5929b4e56bcc4 100644 --- a/src/_locales/pt_BR/messages.json +++ b/src/_locales/pt_BR/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Finalmente, um bloqueador eficiente. Com baixo uso de memória e CPU.", + "message": "Finalmente, um bloqueador eficiente. Com baixo uso de CPU e memória.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "dashboardName": { @@ -1011,6 +1011,10 @@ "message": "Abre abas ou janelas indesejadas", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leva a badware, phishing", + "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\")", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Prosseguir", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Exportar pro armazenamento na nuvem", "description": "tooltip" diff --git a/src/_locales/pt_PT/messages.json b/src/_locales/pt_PT/messages.json index 743b8770b1c0d..0dd6035ce486e 100644 --- a/src/_locales/pt_PT/messages.json +++ b/src/_locales/pt_PT/messages.json @@ -1004,13 +1004,17 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "Falha quando o uBlock Origin é ativado", + "message": "Falha quando o uBlock Origin está ativado", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { "message": "Abre separadores ou janelas indesejáveis", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leva a badware e phishing", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Rotular a página web como “NSFW” (“Não seguro para o trabalho”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Proceder", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Exportar para a nuvem", "description": "tooltip" diff --git a/src/_locales/ro/messages.json b/src/_locales/ro/messages.json index 3881e7821a45a..5aacc0ff2048a 100644 --- a/src/_locales/ro/messages.json +++ b/src/_locales/ro/messages.json @@ -1011,6 +1011,10 @@ "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", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Etichetează pagina ca fiind „NSFW” (“Not Safe For Work”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Continuă", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Exportă către stocarea în cloud", "description": "tooltip" diff --git a/src/_locales/ru/messages.json b/src/_locales/ru/messages.json index 2d535dd32f159..8cd58ef040c49 100644 --- a/src/_locales/ru/messages.json +++ b/src/_locales/ru/messages.json @@ -1,6 +1,6 @@ { "extName": { - "message": "uBlock₀", + "message": "uBlock Origin", "description": "extension name." }, "extShortDesc": { @@ -1011,6 +1011,10 @@ "message": "Открываются нежелательные вкладки или окна", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Вредоносное ПО, фишинг", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Пометить веб-страницу как “NSFW” (“Not Safe For Work”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Продолжить", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Заблокированная страница собирается перенаправить вас на другой сайт. Если вы решите продолжить, вы перейдете непосредственно на: {{url}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Экспорт в облачное хранилище", "description": "tooltip" diff --git a/src/_locales/si/messages.json b/src/_locales/si/messages.json index afd9c19d6f97f..eeafed6f67220 100644 --- a/src/_locales/si/messages.json +++ b/src/_locales/si/messages.json @@ -12,11 +12,11 @@ "description": "English: uBlock₀ — Dashboard" }, "dashboardUnsavedWarning": { - "message": "Warning! You have unsaved changes", + "message": "අවවාදයයි! ඔබ නොසුරැකි වෙනස්කම් ඇත", "description": "A warning in the dashboard when navigating away from unsaved changes" }, "dashboardUnsavedWarningStay": { - "message": "නවතින්න", + "message": "මෙතැන ඉන්න", "description": "Label for button to prevent navigating away from unsaved changes" }, "dashboardUnsavedWarningIgnore": { @@ -28,7 +28,7 @@ "description": "appears as tab name in dashboard" }, "3pPageName": { - "message": "Filter lists", + "message": "පෙරහන් ලැයිස්තු", "description": "appears as tab name in dashboard" }, "1pPageName": { @@ -52,11 +52,11 @@ "description": "Title for the logger window" }, "aboutPageName": { - "message": "පිළිබඳව", + "message": "පිළිබඳ", "description": "appears as tab name in dashboard" }, "supportPageName": { - "message": "Support", + "message": "සහාය", "description": "appears as tab name in dashboard" }, "assetViewerPageName": { @@ -64,7 +64,7 @@ "description": "Title for the asset viewer page" }, "advancedSettingsPageName": { - "message": "වැඩිදුර සැකසුම්", + "message": "සංකීර්ණ සැකසුම්", "description": "Title for the advanced settings page" }, "popupPowerSwitchInfo": { @@ -92,7 +92,7 @@ "description": "Example: 15 (13%)" }, "popupBlockedSinceInstallPrompt": { - "message": "since install", + "message": "ස්ථාපනයේ සිට", "description": "English: since install" }, "popupOr": { @@ -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": { @@ -112,7 +112,7 @@ "description": "For the new mobile-friendly popup design" }, "popupTipDashboard": { - "message": "උපකරණපුවරුව විවෘත කරන්න", + "message": "උපකරණ පුවරුව අරින්න", "description": "English: Click to open the dashboard" }, "popupTipZapper": { @@ -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": { @@ -180,19 +180,19 @@ "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoScripting1": { - "message": "Click to disable JavaScript on this site", + "message": "මෙම අඩවියේ ජාවාස්ක්‍රිප්ට් අබල කිරීමට ඔබන්න", "description": "Tooltip for the no-scripting per-site switch" }, "popupTipNoScripting2": { - "message": "Click to no longer disable JavaScript on this site", + "message": "මෙම අඩවියේ තවදුරටත් ජාවාස්ක්‍රිප්ට් අබල නොකිරීමට ඔබන්න", "description": "Tooltip for the no-scripting per-site switch" }, "popupNoPopups_v2": { - "message": "Pop-up windows", + "message": "උත්පතන කවුළු", "description": "Caption for the no-popups per-site switch" }, "popupNoLargeMedia_v2": { - "message": "Large media elements", + "message": "විශාල මාධ්‍ය අංග", "description": "Caption for the no-large-media per-site switch" }, "popupNoCosmeticFiltering_v2": { @@ -200,11 +200,11 @@ "description": "Caption for the no-cosmetic-filtering per-site switch" }, "popupNoRemoteFonts_v2": { - "message": "දුරස්ථ මුද්‍රණඅකුරු", + "message": "දුරස්ථ රුවකුරු", "description": "Caption for the no-remote-fonts per-site switch" }, "popupNoScripting_v2": { - "message": "JavaScript", + "message": "ජාවාස්ක්‍රිප්ට්", "description": "Caption for the no-scripting per-site switch" }, "popupMoreButton_v2": { @@ -212,7 +212,7 @@ "description": "Label to be used to show popup panel sections" }, "popupLessButton_v2": { - "message": "Less", + "message": "අඩුවෙන්", "description": "Label to be used to hide popup panel sections" }, "popupTipGlobalRules": { @@ -236,31 +236,31 @@ "description": "" }, "popupImageRulePrompt": { - "message": "images", + "message": "රූප", "description": "" }, "popup3pAnyRulePrompt": { - "message": "තෙවන-පාර්ශවීය", + "message": "තෙවන පාර්ශ්ව", "description": "" }, "popup3pPassiveRulePrompt": { - "message": "3rd-party CSS/images", + "message": "තෙවන පාර්ශ්ව CSS/රූප", "description": "" }, "popupInlineScriptRulePrompt": { - "message": "inline scripts", + "message": "එක්තල අත්පත්", "description": "" }, "popup1pScriptRulePrompt": { - "message": "1st-party scripts", + "message": "පළමු පාර්ශ්ව අත්පත්", "description": "" }, "popup3pScriptRulePrompt": { - "message": "3rd-party scripts", + "message": "තෙවන පාර්ශ්ව අත්පත්", "description": "" }, "popup3pFrameRulePrompt": { - "message": "3rd-party frames", + "message": "තෙවන පාර්ශ්ව රාමු", "description": "" }, "popupHitDomainCountPrompt": { @@ -276,11 +276,11 @@ "description": "Example of use: Version 1.26.4" }, "popup3pScriptFilter": { - "message": "script", + "message": "අත්පත", "description": "Appears as an option to filter out firewall rows" }, "popup3pFrameFilter": { - "message": "frame", + "message": "රාමුව", "description": "Appears as an option to filter out firewall rows" }, "pickerCreate": { @@ -308,11 +308,11 @@ "description": "English: Cosmetic filters" }, "pickerCosmeticFiltersHint": { - "message": "Click, Ctrl-click", + "message": "ඔබන්න, Ctrl-ඔබන්න", "description": "English: Click, Ctrl-click" }, "pickerContextMenuEntry": { - "message": "Block element…", + "message": "අංග අවහිර කරන්න", "description": "An entry in the browser's contextual menu" }, "settingsCollapseBlockedPrompt": { @@ -320,7 +320,7 @@ "description": "English: Hide placeholders of blocked elements" }, "settingsIconBadgePrompt": { - "message": "Show the number of blocked requests on the icon", + "message": "නිරූපකයේ අවහිර කළ ඉල්ලීම් ගණන පෙන්වන්න", "description": "English: Show the number of blocked requests on the icon" }, "settingsTooltipsPrompt": { @@ -328,7 +328,7 @@ "description": "A checkbox in the Settings pane" }, "settingsContextMenuPrompt": { - "message": "Make use of context menu where appropriate", + "message": "සුදුසු අවස්ථා වල දී සන්දර්භ වට්ටෝරුව භාවිතා කරන්න", "description": "English: Make use of context menu where appropriate" }, "settingsColorBlindPrompt": { @@ -336,11 +336,11 @@ "description": "English: Color-blind friendly" }, "settingsAppearance": { - "message": "Appearance", + "message": "පෙනුම", "description": "Section for controlling user interface appearance" }, "settingsThemeLabel": { - "message": "Theme", + "message": "තේමාව", "description": "Label for checkbox to enable a custom dark theme" }, "settingsThemeAccent0Label": { @@ -352,7 +352,7 @@ "description": "" }, "settingsAdvancedUserPrompt": { - "message": "I am an advanced user", + "message": "මම ප්‍රගත පරිශ්‍රීලකයෙකි", "description": "Checkbox to let user access advanced, technical features" }, "settingsPrefetchingDisabledPrompt": { @@ -360,7 +360,7 @@ "description": "English: " }, "settingsHyperlinkAuditingDisabledPrompt": { - "message": "Disable hyperlink auditing", + "message": "අතිසබැඳි විගණනය අබල කරන්න", "description": "English: " }, "settingsWebRTCIPAddressHiddenPrompt": { @@ -380,19 +380,19 @@ "description": "" }, "settingsNoLargeMediaPrompt": { - "message": "Block media elements larger than {{input}} KB", + "message": "කි.බ. {{input}} කට වඩා විශාල මාධ්‍ය අංග අවහිර කරන්න", "description": "" }, "settingsNoRemoteFontsPrompt": { - "message": "දුරස්ථ මුද්‍රණඅකුරු බ්ලොක් කරන්න", + "message": "දුරස්ථ රුවකුරු අවහිර කරන්න", "description": "" }, "settingsNoScriptingPrompt": { - "message": "Disable JavaScript", + "message": "ජාවාස්ක්‍රිප්ට් අබල කරන්න", "description": "The default state for the per-site no-scripting switch" }, "settingsNoCSPReportsPrompt": { - "message": "අ.ආ.ප්‍ර.(සීඑස්පී) වාර්තා අවහිරකරන්න", + "message": "අ.ආ.ප්‍ර. (CSP) වාර්තා අවහිර කරන්න", "description": "background information: https://github.com/gorhill/uBlock/issues/3150" }, "settingsUncloakCnamePrompt": { @@ -400,23 +400,23 @@ "description": "background information: https://github.com/uBlockOrigin/uBlock-issues/issues/1513" }, "settingsAdvanced": { - "message": "Advanced", + "message": "සංකීර්ණ", "description": "Section for controlling advanced-user settings" }, "settingsAdvancedSynopsis": { - "message": "Features suitable only for technical users", + "message": "තාක්‍ෂණික පරිශ්‍රීලකයින්ට පමණක් සුදුසු විශේෂාංග", "description": "Description of section controlling advanced-user settings" }, "settingsAdvancedUserSettings": { - "message": "වැඩිදුර සැකසුම්", + "message": "සංකීර්ණ සැකසුම්", "description": "For the tooltip of a link which gives access to advanced settings" }, "settingsLastRestorePrompt": { - "message": "Last restore:", + "message": "අවසාන ප්‍රත්‍යර්පණය:", "description": "English: Last restore:" }, "settingsLastBackupPrompt": { - "message": "Last backup:", + "message": "අවසාන උපස්ථය:", "description": "English: Last backup:" }, "3pListsOfBlockedHostsPrompt": { @@ -432,7 +432,7 @@ "description": "A checkbox in the _3rd-party filters_ pane" }, "3pUpdateNow": { - "message": "දැන් යාවත්කාල කරන්න", + "message": "යාවත්කාල කරන්න", "description": "A button in the in the _3rd-party filters_ pane" }, "3pPurgeAll": { @@ -460,7 +460,7 @@ "description": "A checkbox in the 'Filter lists' pane" }, "3pListsOfBlockedHostsHeader": { - "message": "Lists of blocked hosts", + "message": "අවහිර කළ සත්කාරක", "description": "English: Lists of blocked hosts" }, "3pApplyChanges": { @@ -468,7 +468,7 @@ "description": "English: Apply changes" }, "3pGroupDefault": { - "message": "Built-in", + "message": "තිළෑලි", "description": "Filter lists section name" }, "3pGroupAds": { @@ -476,7 +476,7 @@ "description": "Filter lists section name" }, "3pGroupPrivacy": { - "message": "පෞද්ගලිකත්වය", + "message": "පෞද්ගලිකත්‍වය", "description": "Filter lists section name" }, "3pGroupMalware": { @@ -488,7 +488,7 @@ "description": "Filter lists section name" }, "3pGroupCookies": { - "message": "Cookie notices", + "message": "දත්තකඩ දැන්වීම්", "description": "Filter lists section name" }, "3pGroupAnnoyances": { @@ -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": { @@ -520,7 +520,7 @@ "description": "used as a tooltip for the out-of-date icon beside a list" }, "3pViewContent": { - "message": "view content", + "message": "අන්තර්ගතය බලන්න", "description": "used as a tooltip for eye icon beside a list" }, "3pLastUpdate": { @@ -552,7 +552,7 @@ "description": "Button in the 'My filters' pane" }, "1pExport": { - "message": "නිර්යාත", + "message": "නිර්යාත කරන්න...", "description": "Button in the 'My filters' pane" }, "1pExportFilename": { @@ -572,7 +572,7 @@ "description": "header" }, "rulesRevert": { - "message": "Revert", + "message": "ප්‍රතිවර්තනය", "description": "This will remove all temporary rules" }, "rulesCommit": { @@ -588,11 +588,11 @@ "description": "Will save manually-edited content and exit manual-edit mode" }, "rulesEditDiscard": { - "message": "Discard", + "message": "ඉවතලන්න", "description": "Will discard manually-edited content and exit manual-edit mode" }, "rulesImport": { - "message": "ගොනුවකින් ඇතුල් කරන්න...", + "message": "ගොනුවකින් ආයාත කරන්න...", "description": "" }, "rulesExport": { @@ -600,7 +600,7 @@ "description": "Button in the 'My rules' pane" }, "rulesDefaultFileName": { - "message": "මගේ-ස්ථිර-නීති_{{datetime}}.txt", + "message": "මාගේ-ublock-ගතික-නීති_{{datetime}}.txt", "description": "default file name to use" }, "rulesHint": { @@ -612,7 +612,7 @@ "description": "English: dynamic rule syntax and full documentation." }, "rulesSort": { - "message": "Sort:", + "message": "වර්ගනය:", "description": "English: label for sort option." }, "rulesSortByType": { @@ -620,7 +620,7 @@ "description": "English: a sort option for list of rules." }, "rulesSortBySource": { - "message": "Source", + "message": "මූලාශ්‍රය", "description": "English: a sort option for list of rules." }, "rulesSortByDestination": { @@ -636,11 +636,11 @@ "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { - "message": "නිර්යාත", + "message": "නිර්යාත…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExportFilename": { - "message": "මට-විශ්වාස-වෙබ්-අඩවි_{{datetime}}.txt", + "message": "මාගේ-ublock-විශ්වාසදායී-අඩවි_{{datetime}}.txt", "description": "The default filename to use for import/export purpose" }, "whitelistApply": { @@ -724,23 +724,23 @@ "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": "ප්‍රථම-පාර්ශවීය", + "message": "පළමු පාර්ශ්ව", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltin3p": { - "message": "තෙවන-පාර්ශවීය", + "message": "තෙවන පාර්ශ්ව", "description": "A keyword in the built-in row filtering expression" }, "loggerEntryDetailsHeader": { @@ -752,7 +752,7 @@ "description": "Label to identify a filter field" }, "loggerEntryDetailsFilterList": { - "message": "Filter list", + "message": "පෙරහන් ලැයිස්තුව", "description": "Label to identify a filter list field" }, "loggerEntryDetailsRule": { @@ -760,11 +760,11 @@ "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": { @@ -784,7 +784,7 @@ "description": "Small header to identify the dynamic URL filtering section" }, "loggerURLFilteringContextLabel": { - "message": "Context:", + "message": "සන්දර්භය:", "description": "Label for the context selector" }, "loggerURLFilteringTypeLabel": { @@ -792,7 +792,7 @@ "description": "Label for the type selector" }, "loggerStaticFilteringHeader": { - "message": "Static filter", + "message": "ස්ථිතික පෙරහන", "description": "Small header to identify the static filtering section" }, "loggerStaticFilteringSentence": { @@ -804,7 +804,7 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartAllow": { - "message": "ඉඩදෙන්න", + "message": "ඉඩ දෙන්න", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartType": { @@ -816,7 +816,7 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartOrigin": { - "message": "from “{{origin}}”", + "message": "“{{origin}}” වෙතින්", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartAnyOrigin": { @@ -896,19 +896,19 @@ "description": "Label for radio-button to pick export text format" }, "supportOpenButton": { - "message": "Open", + "message": "අරින්න", "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "නව වාර්තාවක් සාදන්න", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "සමාන වාර්තා සොයන්න", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { - "message": "Documentation", + "message": "ප්‍රලේඛනය", "description": "Header of 'Documentation' section in Support pane" }, "supportS1P1": { @@ -916,7 +916,7 @@ "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": { @@ -940,7 +940,7 @@ "description": "Third paragraph of 'Filter issues' section in Support pane" }, "supportS4H": { - "message": "Bug report", + "message": "දෝෂ වාර්තාව", "description": "Header of 'Bug report' section in Support pane" }, "supportS4P1": { @@ -980,7 +980,7 @@ "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "The web page…", + "message": "වියමන පිටුව…", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { @@ -1011,6 +1011,10 @@ "message": "Opens unwanted tabs or windows", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "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”)", "description": "A checkbox to use for NSFW sites" @@ -1028,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": { @@ -1040,7 +1044,7 @@ "description": "English: Contributors" }, "aboutSourceCode": { - "message": "Source code", + "message": "මූලාශ්‍ර කේත", "description": "Link text to source code repo" }, "aboutTranslations": { @@ -1048,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": { @@ -1072,11 +1076,11 @@ "description": "English: my-ublock-backup_{{datetime}}.txt" }, "aboutRestoreDataButton": { - "message": "ගොනුවකින් ප්‍රත්‍යර්පණය කරන්න...", + "message": "ගොනුවකින් ප්‍රත්‍යර්පණය කරන්න", "description": "English: Restore from file..." }, "aboutResetDataButton": { - "message": "Reset to default settings…", + "message": "සැකසුම් පෙරනිමියට සකසන්න", "description": "English: Reset to default settings..." }, "aboutRestoreDataConfirm": { @@ -1120,7 +1124,7 @@ "description": "English: {{value}} hours ago" }, "elapsedOneDayAgo": { - "message": "දිනකට පෙර", + "message": "දවසකට පෙර", "description": "English: a day ago" }, "elapsedManyDaysAgo": { @@ -1136,11 +1140,11 @@ "description": "Firefox/Fennec-specific: Show Logger" }, "fennecMenuItemBlockingOff": { - "message": "off", + "message": "අක්‍රියයි", "description": "Firefox-specific: appears as 'uBlock₀ (off)'" }, "docblockedTitle": { - "message": "Page blocked", + "message": "පිටුව අවහිරයි", "description": "Used as a title for the document-blocked page" }, "docblockedPrompt1": { @@ -1156,7 +1160,7 @@ "description": "label to be used for the parameter-less URL: https://cloud.githubusercontent.com/assets/585534/9832014/bfb1b8f0-593b-11e5-8a27-fba472a5529a.png" }, "docblockedFoundIn": { - "message": "Found in:", + "message": "මෙහි හමු විය:", "description": "English: List of filter list names follows" }, "docblockedBack": { @@ -1180,13 +1184,17 @@ "description": "English: Temporarily" }, "docblockedDisablePermanent": { - "message": "සදාකාලිකව", + "message": "සදහටම", "description": "English: Permanently" }, "docblockedDisable": { "message": "Proceed", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "මේඝ ආචයනයට නිර්යාත කරන්න", "description": "tooltip" @@ -1196,7 +1204,7 @@ "description": "tooltip" }, "cloudPullAndMerge": { - "message": "මේඝ ආචයනයෙන් ආයාත කර වත්මන් සැකසුම් සමඟ සංයුක්ත කරන්න", + "message": "මේඝ ආචයනයෙන් ආයාත කර වත්මන් සැකසුම් වලට ඒකාබද්ධ කරන්න", "description": "tooltip" }, "cloudNoData": { @@ -1208,11 +1216,11 @@ "description": "used as a prompt for the user to provide a custom device name" }, "advancedSettingsWarning": { - "message": "Warning! Change these advanced settings at your own risk.", + "message": "අවවාදයයි! මෙම සංකීර්ණ සැකසුම් සංශෝධනයේ අවදානම ඔබ සතුයි.", "description": "A warning to users at the top of 'Advanced settings' page" }, "genericSubmit": { - "message": "Submit", + "message": "යොමන්න", "description": "for generic 'Submit' buttons" }, "genericApplyChanges": { @@ -1220,7 +1228,7 @@ "description": "for generic 'Apply changes' buttons" }, "genericRevert": { - "message": "Revert", + "message": "ප්‍රතිවර්තනය", "description": "for generic 'Revert' buttons" }, "genericBytes": { @@ -1240,11 +1248,11 @@ "description": "A context menu entry, present when large media elements have been blocked on the current site" }, "contextMenuViewSource": { - "message": "View source code…", + "message": "මූලාශ්‍ර කේත බලන්න…", "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": { @@ -1252,11 +1260,11 @@ "description": "Tooltip for the button used to lock scrolling between the views in the 'My rules' pane" }, "genericCopyToClipboard": { - "message": "පසුරුපුවරුවට පිටපත් කරන්න", + "message": "පසුරු පුවරුවට පිටපතක්", "description": "Label for buttons used to copy something to the clipboard" }, "genericSelectAll": { - "message": "Select all", + "message": "සියල්ල තෝරන්න", "description": "Label for buttons used to select all text in editor" }, "toggleCosmeticFiltering": { @@ -1272,7 +1280,7 @@ "description": "Label for keyboard shortcut used to relax blocking mode" }, "storageUsed": { - "message": "Storage used: {{value}} {{unit}}", + "message": "ආචයනය භාවිතය: {{value}} {{unit}}", "description": " In Setting pane, renders as (example): Storage used: 13.2 MB" }, "KB": { @@ -1292,7 +1300,7 @@ "description": "Message used in frame placeholders" }, "linterMainReport": { - "message": "Errors: {{count}}", + "message": "දෝෂ: {{count}}", "description": "Summary of number of errors as reported by the linter " }, "unprocessedRequestTooltip": { diff --git a/src/_locales/sk/messages.json b/src/_locales/sk/messages.json index ab778d9d25cf9..04d46777ce198 100644 --- a/src/_locales/sk/messages.json +++ b/src/_locales/sk/messages.json @@ -1011,6 +1011,10 @@ "message": "Otvára nechcené karty alebo okná", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Smeruje k badvéru a phishingu", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Označiť webstránku ako “NSFW” (Nie je bezpečné pre prácu”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Pokračovať", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Exportovať do cloudového úložiska", "description": "tooltip" diff --git a/src/_locales/sl/messages.json b/src/_locales/sl/messages.json index bb2cfa2e156d5..201ae9988a820 100644 --- a/src/_locales/sl/messages.json +++ b/src/_locales/sl/messages.json @@ -1011,6 +1011,10 @@ "message": "Opens unwanted tabs or windows", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "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”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Proceed", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Izvozi v shrambe oblaka", "description": "tooltip" diff --git a/src/_locales/so/messages.json b/src/_locales/so/messages.json index b8c9c13bcef31..c0ba2c7c70356 100644 --- a/src/_locales/so/messages.json +++ b/src/_locales/so/messages.json @@ -1011,6 +1011,10 @@ "message": "Opens unwanted tabs or windows", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "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”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Proceed", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "{{value}} saac kahor", "description": "tooltip" diff --git a/src/_locales/sq/messages.json b/src/_locales/sq/messages.json index 3fc972c4b03cb..8fa200e0bb16b 100644 --- a/src/_locales/sq/messages.json +++ b/src/_locales/sq/messages.json @@ -1011,6 +1011,10 @@ "message": "Hap skeda ose dritare të panevojshme", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Çon në instalimin e programeve keqdashëse, mashtruese", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Etiketoj faqen si “NSFW” (“E papërshtatshme për punë”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Vazhdoj", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Eksportoni në renë informatike", "description": "tooltip" diff --git a/src/_locales/sr/messages.json b/src/_locales/sr/messages.json index 35e56fc77a59b..1e4f7d6d91df2 100644 --- a/src/_locales/sr/messages.json +++ b/src/_locales/sr/messages.json @@ -548,11 +548,11 @@ "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": { - "message": "Извези", + "message": "Извези…", "description": "Button in the 'My filters' pane" }, "1pExportFilename": { @@ -928,7 +928,7 @@ "description": "Header of 'Filter issues' section in Support pane" }, "supportS3P1": { - "message": "Пријавите проблеме са филтерима на одређеним веб сајтовима на uBlockOrigin/uAssets, страници за праћење проблема. Неопходан је GitHub налог.", + "message": "Пријавите проблеме са филтерима на одређеним веб сајтовима на uBlockOrigin/uAssets issue tracker. Неопходан је GitHub налог.", "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { @@ -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 issue tracker. Неопходан је GitHub налог.", "description": "First paragraph of 'Bug report' section in Support pane" }, "supportS5H": { @@ -1011,6 +1011,10 @@ "message": "\nОтвара нежељене картице или прозоре", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Води до лошег софтвера, „пецања\"", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Изначите веб страницу као „NSFW“ (“Није безбедна за рад”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Настави", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Блокирана страница жели да преусмери на други сајт. Ако одлучите да наставите, ићи ћете директно на: {{url}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Извези у складиште у облаку", "description": "tooltip" diff --git a/src/_locales/sv/messages.json b/src/_locales/sv/messages.json index 37a8070e4e476..e1dbccb445bb8 100644 --- a/src/_locales/sv/messages.json +++ b/src/_locales/sv/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Äntligen en effektiv blockerare. Snäll mot både processor och minne.", + "message": "Äntligen en effektiv blockerare. Skonsam mot både processor och minne.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "dashboardName": { @@ -928,7 +928,7 @@ "description": "Header of 'Filter issues' section in Support pane" }, "supportS3P1": { - "message": "Rapportera filterproblem med specifika webbplatser till uBlockOrigin/uAssets problemhanteringssystemet. Kräver ett GitHub-konto.", + "message": "Rapportera filterproblem med specifika webbplatser till problemhanteringssystemet uBlockOrigin/uAssets. Kräver ett GitHub-konto.", "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { @@ -944,7 +944,7 @@ "description": "Header of 'Bug report' section in Support pane" }, "supportS4P1": { - "message": "Rapportera problem med själva uBlock Origin till uBlockOrigin/uBlock-issue ärendehanteringssystemet. Kräver ett GitHub-konto.", + "message": "Rapportera problem med själva uBlock Origin till problemhanteringssystemet uBlockOrigin/uBlock-issue. Kräver ett GitHub-konto.", "description": "First paragraph of 'Bug report' section in Support pane" }, "supportS5H": { @@ -1011,6 +1011,10 @@ "message": "Öppnar oönskade flikar eller fönster", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leder till skadlig programvara, nätfiske", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Märk webbsidan som \"NSFW\" (“Inte lämplig på jobbet”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Fortsätt", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Exportera till molnlagring", "description": "tooltip" diff --git a/src/_locales/sw/messages.json b/src/_locales/sw/messages.json index ad3e42820fc88..5ecd7de52bfab 100644 --- a/src/_locales/sw/messages.json +++ b/src/_locales/sw/messages.json @@ -1011,6 +1011,10 @@ "message": "Hufungua vichupo au vidirisha visivyotakikana", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Ipe tovuti lebo ya \"NSFW\" (\"Haifai Kazini\")", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Proceed", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Hamisha hadi hifadhi ya wingu", "description": "tooltip" diff --git a/src/_locales/ta/messages.json b/src/_locales/ta/messages.json index c76293554b4ca..262a988ed4256 100644 --- a/src/_locales/ta/messages.json +++ b/src/_locales/ta/messages.json @@ -1011,6 +1011,10 @@ "message": "தேவையற்ற தாவல்கள் அ சாளரங்களைத் திறக்கிறது", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "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”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Proceed", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "மேகக்கணினி சேமிப்பகத்திற்கு ஏற்று", "description": "tooltip" diff --git a/src/_locales/te/messages.json b/src/_locales/te/messages.json index 0f4e085e0c91a..68ebfc80a0801 100644 --- a/src/_locales/te/messages.json +++ b/src/_locales/te/messages.json @@ -1011,6 +1011,10 @@ "message": "అనవసరమైన ట్యాబ్‌లు లేదా విండోలను తెరుస్తుంది", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "వెబ్ పేజీని “NSFW”గా లేబుల్ చేయండి (“పని కోసం సురక్షితం కాదు”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Proceed", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "క్లౌడ్ లో పొందుపరచు", "description": "tooltip" diff --git a/src/_locales/th/messages.json b/src/_locales/th/messages.json index 268cd4da0366d..55ba15a03f0a6 100644 --- a/src/_locales/th/messages.json +++ b/src/_locales/th/messages.json @@ -1011,6 +1011,10 @@ "message": "Opens unwanted tabs or windows", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "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”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff --git a/src/_locales/tr/messages.json b/src/_locales/tr/messages.json index 31f6aa55ca6ee..f3d2276db5950 100644 --- a/src/_locales/tr/messages.json +++ b/src/_locales/tr/messages.json @@ -484,7 +484,7 @@ "description": "Filter lists section name" }, "3pGroupSocial": { - "message": "Sosyal gereçler", + "message": "Sosyal medya tuşları", "description": "Filter lists section name" }, "3pGroupCookies": { @@ -548,11 +548,11 @@ "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { - "message": "İçe aktar ve ekle", + "message": "İçe aktar ve ekle…", "description": "Button in the 'My filters' pane" }, "1pExport": { - "message": "Dışa aktar", + "message": "Dışa aktar…", "description": "Button in the 'My filters' pane" }, "1pExportFilename": { @@ -636,7 +636,7 @@ "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { - "message": "Dışa aktar", + "message": "Dışa aktar…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExportFilename": { @@ -1011,6 +1011,10 @@ "message": "İstenmeyen sekme veya pencereler açıyor", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Kötü niyetli yazılıma yönlendiriyor, oltalama", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Web sayfasını uygunsuz (“NSFW”) olarak etiketle (“Not Safe For Work”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Devam et", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Bulut depolamaya aktar", "description": "tooltip" diff --git a/src/_locales/uk/messages.json b/src/_locales/uk/messages.json index c78caea505588..aeb7440ad3adf 100644 --- a/src/_locales/uk/messages.json +++ b/src/_locales/uk/messages.json @@ -108,7 +108,7 @@ "description": "For the new mobile-friendly popup design" }, "popupDomainsConnected_v2": { - "message": "Доменів під'єднано", + "message": "Підключені домени", "description": "For the new mobile-friendly popup design" }, "popupTipDashboard": { @@ -336,7 +336,7 @@ "description": "English: Color-blind friendly" }, "settingsAppearance": { - "message": "Вигляд", + "message": "Зовнішній вигляд", "description": "Section for controlling user interface appearance" }, "settingsThemeLabel": { @@ -344,7 +344,7 @@ "description": "Label for checkbox to enable a custom dark theme" }, "settingsThemeAccent0Label": { - "message": "Акцент кольору користувача", + "message": "Індивідуальний колір акценту", "description": "Label for checkbox to pick an accent color" }, "settingsCloudStorageEnabledPrompt": { @@ -1011,6 +1011,10 @@ "message": "Відкриває небажані вкладки або вікна", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Веде до шкідливого ПЗ, фішингу", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "Позначити цю сторінку «NSFW» («Небезпечно для роботи»)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Продовжити", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Заблокована сторінка хоче переадресувати на інший сайт. Якщо ви вирішите продовжити, ви перейдете безпосередньо на: {{url}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "Експортувати до хмарного сховища", "description": "tooltip" diff --git a/src/_locales/ur/messages.json b/src/_locales/ur/messages.json index 6fbc6fcc824a5..ec794cbfb966e 100644 --- a/src/_locales/ur/messages.json +++ b/src/_locales/ur/messages.json @@ -1011,6 +1011,10 @@ "message": "Opens unwanted tabs or windows", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Leads to badware, phishing", + "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”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "Proceed", "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}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "کلاؤڈ سٹوریج میں برآمد کریں", "description": "tooltip" diff --git a/src/_locales/vi/messages.json b/src/_locales/vi/messages.json index 9c50188234059..bfea4310a0f38 100644 --- a/src/_locales/vi/messages.json +++ b/src/_locales/vi/messages.json @@ -140,7 +140,7 @@ "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoPopups2": { - "message": "Nhấn để bỏ chặn tất cả cửa sổ bật lên trên trang này", + "message": "Nhấp để bỏ chặn tất cả cửa sổ bật lên trên trang này", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoLargeMedia": { @@ -480,7 +480,7 @@ "description": "Filter lists section name" }, "3pGroupMalware": { - "message": "Bảo mật, bảo vệ khỏi phần mềm nguy hiểm", + "message": "Bảo mật, bảo vệ khỏi phần mềm độc hại", "description": "Filter lists section name" }, "3pGroupSocial": { @@ -628,7 +628,7 @@ "description": "English: a sort option for list of rules." }, "whitelistPrompt": { - "message": "Các chỉ thị trang web đáng tin cậy ra lệnh trên đó các trang web uBlock Origin sẽ bị vô hiệu hóa. Một mục nhập cho mỗi dòng. Chỉ thị không hợp lệ sẽ được âm thầm bỏ qua và nhận xét ra.", + "message": "Các đường dẫn trang web đáng tin cậy cố định mà uBlock Origin sẽ bị vô hiệu hóa trên trang đó. Một mục nhập cho mỗi dòng.", "description": "A concise description of the 'Trusted sites' pane." }, "whitelistImport": { @@ -640,7 +640,7 @@ "description": "Button in the 'Trusted sites' pane" }, "whitelistExportFilename": { - "message": "my-ublock-whitelist_{{datetime}}.txt", + "message": "my-ublock-trusted-sites_{{datetime}}.txt", "description": "The default filename to use for import/export purpose" }, "whitelistApply": { @@ -844,11 +844,11 @@ "description": "Logger setting: A sentence to describe the purpose of the settings below" }, "loggerSettingPerEntryMaxAge": { - "message": "Bảo tồn các mục từ {{input}} phút trước", + "message": "Giữ lại các mục từ {{input}} phút trước", "description": "A logger setting" }, "loggerSettingPerTabMaxLoads": { - "message": "Bảo tồn nhiều nhất {{input}} trang được tải trên mỗi thẻ", + "message": "Giữ lại nhiều nhất {{input}} trang được tải trên mỗi thẻ", "description": "A logger setting" }, "loggerSettingPerTabMaxEntries": { @@ -928,7 +928,7 @@ "description": "Header of 'Filter issues' section in Support pane" }, "supportS3P1": { - "message": "Cần tài khoản GitHub: Báo cáo lỗi bộ lọc với tên miền cụ thể cho uBlock Origin tại đây. ", + "message": "Báo cáo lỗi bộ lọc với tên miền cụ thể cho uBlockOrigin/uAssets issue tracker. Cần tài khoản GitHub ", "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { @@ -944,7 +944,7 @@ "description": "Header of 'Bug report' section in Support pane" }, "supportS4P1": { - "message": "Cần tài khoản GitHub: Báo cáo lỗi bộ lọc với tên miền cụ thể cho uBlock Origin tại đây. ", + "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": { @@ -968,7 +968,7 @@ "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { - "message": "Danh sách bộ lọc được cập nhật hàng ngày. Đảm bảo vấn đề của bạn chưa được giải quyết trong danh sách bộ lọc gần đây nhất.", + "message": "Danh sách bộ lọc được cập nhật hàng ngày. Hãy đảm bảo vấn đề của bạn chưa được giải quyết trong danh sách bộ lọc gần đây nhất.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S2": { @@ -984,7 +984,7 @@ "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { - "message": "--Chọn một lỗi--", + "message": "-- Chọn một lỗi --", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { @@ -1011,6 +1011,10 @@ "message": "Xuất hiện các tab và cửa sổ ngoài mong muốn", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "Dẫn đến phần mềm độc hại, lừa đảo", + "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\"", "description": "A checkbox to use for NSFW sites" @@ -1096,7 +1100,7 @@ "description": "English: Network error: {{msg}}" }, "subscriberConfirm": { - "message": "uBlock₀: Thêm URL dưới đây vào bộ lọc tuỳ biến của bạn?\n\nTên: \"{{title}}\"\nURL: {{url}}", + "message": "Thêm URL dưới đây vào bộ lọc tuỳ biến của bạn?\n\nTên: \"{{title}}\"\nURL: {{url}}", "description": "No longer used" }, "subscribeButton": { @@ -1187,6 +1191,10 @@ "message": "Tiếp tục", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "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" + }, "cloudPush": { "message": "Xuất ra lưu trữ trực tuyến", "description": "tooltip" @@ -1240,7 +1248,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": { @@ -1272,7 +1280,7 @@ "description": "Label for keyboard shortcut used to relax blocking mode" }, "storageUsed": { - "message": "Bộ nhớ đã dùng: {{value}} byte", + "message": "Bộ nhớ đã dùng: {{value}} {{unit}}", "description": " In Setting pane, renders as (example): Storage used: 13.2 MB" }, "KB": { diff --git a/src/_locales/zh_CN/messages.json b/src/_locales/zh_CN/messages.json index 8e1acd8f3efd4..651c4224d6862 100644 --- a/src/_locales/zh_CN/messages.json +++ b/src/_locales/zh_CN/messages.json @@ -1011,6 +1011,10 @@ "message": "打开不需要的标签页或窗口", "description": "An entry in the widget used to select the type of issue" }, + "supportS6Select1Option7": { + "message": "指向恶意软件、钓鱼网站", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "message": "将该网页标记为 “NSFW”(“工作场所不宜”)", "description": "A checkbox to use for NSFW sites" @@ -1187,6 +1191,10 @@ "message": "继续加载", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "被屏蔽的网页想重定向到另一个网站。如果您选择继续,将直接导航到:{{url}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "导出到云端储存", "description": "tooltip" diff --git a/src/_locales/zh_TW/messages.json b/src/_locales/zh_TW/messages.json index f07258b6a40cb..92923a9e122c8 100644 --- a/src/_locales/zh_TW/messages.json +++ b/src/_locales/zh_TW/messages.json @@ -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": { @@ -12,7 +12,7 @@ "description": "English: uBlock₀ — Dashboard" }, "dashboardUnsavedWarning": { - "message": "警告!您有尚未儲存的變更", + "message": "警告!變更尚未儲存。", "description": "A warning in the dashboard when navigating away from unsaved changes" }, "dashboardUnsavedWarningStay": { @@ -40,7 +40,7 @@ "description": "appears as tab name in dashboard" }, "whitelistPageName": { - "message": "受信任網站", + "message": "白名單", "description": "appears as tab name in dashboard" }, "shortcutsPageName": { @@ -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": { @@ -152,7 +152,7 @@ "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoLargeMedia2": { - "message": "點擊以停止封鎖此網站的大型媒體元素", + "message": "點擊以解除封鎖此網站的大型媒體元素", "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoCosmeticFiltering": { @@ -176,7 +176,7 @@ "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoRemoteFonts2": { - "message": "點擊以停止封鎖此網站的遠端字型", + "message": "點擊以解除封鎖此網站的遠端字型", "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoScripting1": { @@ -200,7 +200,7 @@ "description": "Caption for the no-cosmetic-filtering per-site switch" }, "popupNoRemoteFonts_v2": { - "message": "遠端字體", + "message": "遠端字型", "description": "Caption for the no-remote-fonts per-site switch" }, "popupNoScripting_v2": { @@ -276,11 +276,11 @@ "description": "Example of use: Version 1.26.4" }, "popup3pScriptFilter": { - "message": "腳本", + "message": "程式碼", "description": "Appears as an option to filter out firewall rows" }, "popup3pFrameFilter": { - "message": "框架", + "message": "框架元素", "description": "Appears as an option to filter out firewall rows" }, "pickerCreate": { @@ -324,7 +324,7 @@ "description": "English: Show the number of blocked requests on the icon" }, "settingsTooltipsPrompt": { - "message": "關閉提示文字功能", + "message": "停用提示框", "description": "A checkbox in the Settings pane" }, "settingsContextMenuPrompt": { @@ -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": "防止「網頁即時通訊」洩漏本地 IP 位址", "description": "English: " }, "settingPerSiteSwitchGroup": { @@ -396,7 +396,7 @@ "description": "background information: https://github.com/gorhill/uBlock/issues/3150" }, "settingsUncloakCnamePrompt": { - "message": "揭露網域真實名稱", + "message": "揭露網域「正規名稱」", "description": "background information: https://github.com/uBlockOrigin/uBlock-issues/issues/1513" }, "settingsAdvanced": { @@ -404,7 +404,7 @@ "description": "Section for controlling advanced-user settings" }, "settingsAdvancedSynopsis": { - "message": "僅適合技術性使用者的功能", + "message": "僅合適技術使用者的功能", "description": "Description of section controlling advanced-user settings" }, "settingsAdvancedUserSettings": { @@ -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,7 +452,7 @@ "description": "This will cause uBO to ignore all generic cosmetic filters." }, "3pIgnoreGenericCosmeticFiltersInfo": { - "message": "「通用元素隱藏過濾規則」是會套用在所有網站上的元素隱藏過濾規則。啟用此選項會消除網頁處理此類規則時增加的額外記憶體與 CPU 使用量。\n\n建議在較低效能的裝置上啟用此選項。", + "message": "「通用元素過濾規則」是會套用在所有網站上的網頁元素過濾規則。啟用此選項會消除網頁處理此類規則時增加的額外記憶體與 CPU 使用量。\n\n建議在效能較弱的裝置上啟用此選項。", "description": "Describes the purpose of the 'Ignore generic cosmetic filters' feature." }, "3pSuspendUntilListsAreLoaded": { @@ -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": { @@ -992,7 +992,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": { @@ -1000,7 +1000,7 @@ "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": { @@ -1008,7 +1008,11 @@ "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": "導致惡意軟體、網路釣魚", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { @@ -1140,7 +1144,7 @@ "description": "Firefox-specific: appears as 'uBlock₀ (off)'" }, "docblockedTitle": { - "message": "頁面已阻擋", + "message": "已封鎖頁面", "description": "Used as a title for the document-blocked page" }, "docblockedPrompt1": { @@ -1187,6 +1191,10 @@ "message": "繼續載入", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "被封鎖的網頁想要重新導向至其他網站。如果您選擇繼續,則會直接前往:{{url}}", + "description": "Text warning about an incoming redirect" + }, "cloudPush": { "message": "匯出至雲端儲存空間", "description": "tooltip" @@ -1208,7 +1216,7 @@ "description": "used as a prompt for the user to provide a custom device name" }, "advancedSettingsWarning": { - "message": "警告!修改進階設定時請自負風險。", + "message": "警告!修改進階設定時,請自負風險。", "description": "A warning to users at the top of 'Advanced settings' page" }, "genericSubmit": { @@ -1244,7 +1252,7 @@ "description": "A context menu entry, to view the source code of the target resource" }, "shortcutCapturePlaceholder": { - "message": "輸入快捷鍵", + "message": "鍵入快速鍵", "description": "Placeholder string for input field used to capture a keyboard shortcut" }, "genericMergeViewScrollLock": { @@ -1296,7 +1304,7 @@ "description": "Summary of number of errors as reported by the linter " }, "unprocessedRequestTooltip": { - "message": "無法在瀏覽器啟動的時候正確過濾頁面。請重新載入來確保過濾正確。", + "message": "無法在瀏覽器啟動時正確過濾頁面。請重新載入以確保過濾正常。", "description": "A warning which will appear in the popup panel if needed" }, "dummy": { diff --git a/src/css/codemirror.css b/src/css/codemirror.css index 9036acc990182..d1ca9fa1008de 100644 --- a/src/css/codemirror.css +++ b/src/css/codemirror.css @@ -134,6 +134,10 @@ .cm-theme-override .cm-s-default .cm-variable { color: var(--sf-variable-ink); } +.cm-theme-override .cm-s-default .CodeMirror-activeline .cm-ext-js .cm-variable { + text-decoration: underline color-mix(in srgb, var(--sf-variable-ink) 30%, transparent) solid 3px; + text-decoration-skip-ink: none; + } .cm-theme-override .cm-s-default .cm-warning { background-color: var(--sf-warning-surface); text-decoration: underline var(--sf-warning-ink); diff --git a/src/css/document-blocked.css b/src/css/document-blocked.css index 62d49216a5b03..75fa392f0a06a 100644 --- a/src/css/document-blocked.css +++ b/src/css/document-blocked.css @@ -28,12 +28,18 @@ body { } #rootContainer { - width: min(100vw, 640px); + width: min(100%, 640px); } #rootContainer > * { margin: 0 0 var(--default-gap-xxlarge) 0; } +:root.mobile #rootContainer > * { + margin-bottom: var(--default-gap-xlarge); + } +p { + margin: 0.5em 0; + } a { text-decoration: none; } @@ -45,8 +51,12 @@ a { color: var(--accent-surface-1); fill: var(--accent-surface-1); font-size: 96px; + line-height: 1; width: 100%; } +:root.mobile #warningSign { + font-size: 64px; + } #theURL { color: var(--ink-2); padding: 0; @@ -58,6 +68,14 @@ a { position: relative; z-index: 10; } +#theURL > p > span:first-of-type { + display: block; + max-height: 6lh; + overflow-y: auto; + } +:root.mobile #theURL > p > span:first-of-type { + max-height: 3lh; + } #theURL #toggleParse { background-color: transparent; top: 100%; @@ -120,6 +138,15 @@ body[dir="rtl"] #toggleParse { padding-inline-start: var(--default-gap-xsmall); } +#urlskip a { + display: block; + overflow-y: auto; + word-break: break-all; + } +:root.mobile #urlskip a { + max-height: 3lh; + } + #actionContainer { display: flex; justify-content: space-between; diff --git a/src/document-blocked.html b/src/document-blocked.html index 80a45461afd7f..4c69359f1664e 100644 --- a/src/document-blocked.html +++ b/src/document-blocked.html @@ -33,6 +33,9 @@
+ +
@@ -42,13 +45,14 @@ - - + + diff --git a/src/js/arglist-parser.js b/src/js/arglist-parser.js new file mode 100644 index 0000000000000..d8200df5822a1 --- /dev/null +++ b/src/js/arglist-parser.js @@ -0,0 +1,116 @@ +/******************************************************************************* + + 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 +*/ + +/******************************************************************************/ + +export class ArglistParser { + constructor(separatorChar = ',', mustQuote = false) { + this.separatorChar = this.actualSeparatorChar = separatorChar; + this.separatorCode = this.actualSeparatorCode = separatorChar.charCodeAt(0); + this.mustQuote = mustQuote; + this.quoteBeg = 0; this.quoteEnd = 0; + this.argBeg = 0; this.argEnd = 0; + this.separatorBeg = 0; this.separatorEnd = 0; + this.transform = false; + this.failed = false; + this.reWhitespaceStart = /^\s+/; + this.reWhitespaceEnd = /\s+$/; + this.reOddTrailingEscape = /(?:^|[^\\])(?:\\\\)*\\$/; + this.reTrailingEscapeChars = /\\+$/; + } + nextArg(pattern, beg = 0) { + const len = pattern.length; + this.quoteBeg = beg + this.leftWhitespaceCount(pattern.slice(beg)); + this.failed = false; + const qc = pattern.charCodeAt(this.quoteBeg); + if ( qc === 0x22 /* " */ || qc === 0x27 /* ' */ || qc === 0x60 /* ` */ ) { + this.indexOfNextArgSeparator(pattern, qc); + if ( this.argEnd !== len ) { + this.quoteEnd = this.argEnd + 1; + this.separatorBeg = this.separatorEnd = this.quoteEnd; + this.separatorEnd += this.leftWhitespaceCount(pattern.slice(this.quoteEnd)); + if ( this.separatorEnd === len ) { return this; } + if ( pattern.charCodeAt(this.separatorEnd) === this.separatorCode ) { + this.separatorEnd += 1; + return this; + } + } + } + this.indexOfNextArgSeparator(pattern, this.separatorCode); + this.separatorBeg = this.separatorEnd = this.argEnd; + if ( this.separatorBeg < len ) { + this.separatorEnd += 1; + } + this.argEnd -= this.rightWhitespaceCount(pattern.slice(0, this.separatorBeg)); + this.quoteEnd = this.argEnd; + if ( this.mustQuote ) { + this.failed = true; + } + return this; + } + normalizeArg(s, char = '') { + if ( char === '' ) { char = this.actualSeparatorChar; } + let out = ''; + let pos = 0; + while ( (pos = s.lastIndexOf(char)) !== -1 ) { + out = s.slice(pos) + out; + s = s.slice(0, pos); + const match = this.reTrailingEscapeChars.exec(s); + if ( match === null ) { continue; } + const tail = (match[0].length & 1) !== 0 + ? match[0].slice(0, -1) + : match[0]; + out = tail + out; + s = s.slice(0, -match[0].length); + } + if ( out === '' ) { return s; } + return s + out; + } + leftWhitespaceCount(s) { + const match = this.reWhitespaceStart.exec(s); + return match === null ? 0 : match[0].length; + } + rightWhitespaceCount(s) { + const match = this.reWhitespaceEnd.exec(s); + return match === null ? 0 : match[0].length; + } + indexOfNextArgSeparator(pattern, separatorCode) { + this.argBeg = this.argEnd = separatorCode !== this.separatorCode + ? this.quoteBeg + 1 + : this.quoteBeg; + this.transform = false; + if ( separatorCode !== this.actualSeparatorCode ) { + this.actualSeparatorCode = separatorCode; + this.actualSeparatorChar = String.fromCharCode(separatorCode); + } + while ( this.argEnd < pattern.length ) { + const pos = pattern.indexOf(this.actualSeparatorChar, this.argEnd); + if ( pos === -1 ) { + return (this.argEnd = pattern.length); + } + if ( this.reOddTrailingEscape.test(pattern.slice(0, pos)) === false ) { + return (this.argEnd = pos); + } + this.transform = true; + this.argEnd = pos + 1; + } + } +} diff --git a/src/js/assets.js b/src/js/assets.js index e1bc4e616a3ea..4f02700f8c46e 100644 --- a/src/js/assets.js +++ b/src/js/assets.js @@ -19,18 +19,15 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ +import * as sfp from './static-filtering-parser.js'; -import µb from './background.js'; import { broadcast } from './broadcast.js'; import cacheStorage from './cachestorage.js'; -import { ubolog } from './console.js'; import { i18n$ } from './i18n.js'; import logger from './logger.js'; -import * as sfp from './static-filtering-parser.js'; -import { orphanizeString, } from './text-utils.js'; +import { orphanizeString } from './text-utils.js'; +import { ubolog } from './console.js'; +import µb from './background.js'; /******************************************************************************/ @@ -50,6 +47,9 @@ let remoteServerFriendly = false; /******************************************************************************/ +const hasOwnProperty = (o, p) => + Object.prototype.hasOwnProperty.call(o, p); + const stringIsNotEmpty = s => typeof s === 'string' && s !== ''; const parseExpires = s => { @@ -107,8 +107,8 @@ const resourceTimeFromXhr = xhr => { const resourceTimeFromParts = (parts, time) => { const goodParts = parts.filter(part => typeof part === 'object'); - return goodParts.reduce((acc, part) => - ((part.resourceTime || 0) > acc ? part.resourceTime : acc), + return goodParts.reduce( + (acc, part) => ((part.resourceTime || 0) > acc ? part.resourceTime : acc), time ); }; @@ -246,6 +246,7 @@ const fireNotification = function(topic, details) { assets.fetch = function(url, options = {}) { return new Promise((resolve, reject) => { // Start of executor + /* eslint-disable indent */ const timeoutAfter = µb.hiddenSettings.assetFetchTimeout || 30; const xhr = new XMLHttpRequest(); @@ -322,6 +323,7 @@ assets.fetch = function(url, options = {}) { onErrorEvent.call(xhr); } + /* eslint-enable indent */ // End of executor }); }; @@ -733,7 +735,7 @@ async function assetCacheRead(assetKey, updateReadTime = false) { } if ( bin instanceof Object === false ) { return reportBack(''); } - if ( bin.hasOwnProperty(internalKey) === false ) { return reportBack(''); } + if ( hasOwnProperty(bin, internalKey) === false ) { return reportBack(''); } const entry = assetCacheRegistry[assetKey]; if ( entry === undefined ) { return reportBack(''); } @@ -1277,7 +1279,9 @@ async function diffUpdater() { if ( data.status === 'needtext' ) { ubolog('Diff updater: need text for', data.assetKey); assetCacheRead(data.assetKey).then(result => { - data.text = result.content; + // https://bugzilla.mozilla.org/show_bug.cgi?id=1929326#c9 + // Must never be set to undefined! + data.text = result.content || ''; data.status = undefined; checkAndCorrectDiffPath(data); bc.postMessage(data); diff --git a/src/js/background.js b/src/js/background.js index edeac08935de9..01fd3b5d6b1ec 100644 --- a/src/js/background.js +++ b/src/js/background.js @@ -59,20 +59,21 @@ const hiddenSettingsDefault = { cnameIgnore1stParty: true, cnameIgnoreExceptions: true, cnameIgnoreRootDocument: true, - cnameMaxTTL: 120, cnameReplayFullURL: false, - cnameUncloakProxied: false, consoleLogLevel: 'unset', debugAssetsJson: false, debugScriptlets: false, debugScriptletInjector: false, differentialUpdate: true, disableWebAssembly: false, + dnsCacheTTL: 600, + dnsResolveEnabled: true, extensionUpdateForceReload: false, filterAuthorMode: false, loggerPopupType: 'popup', manualUpdateAssetFetchPeriod: 500, modifyWebextFlavor: 'unset', + noScriptingCSP: 'script-src http: https:', popupFontSize: 'unset', popupPanelDisabledSections: 0, popupPanelHeightMode: 0, @@ -254,7 +255,6 @@ const µBlock = { // jshint ignore:line scriptlets: {}, cspNoInlineScript: "script-src 'unsafe-eval' * blob: data:", - cspNoScripting: 'script-src http: https:', cspNoInlineFont: 'font-src *', liveBlockingProfiles: [], @@ -306,6 +306,7 @@ const µBlock = { // jshint ignore:line this.realm = ''; this.setMethod(details.method); this.setURL(details.url); + this.setIPAddress(details.ip); this.aliasURL = details.aliasURL || undefined; this.redirectURL = undefined; this.filter = undefined; @@ -346,7 +347,7 @@ const µBlock = { // jshint ignore:line this.setDocOrigin(origin).setTabOrigin(origin); return this; } - const origin = (this.itype & this.FRAME_ANY) !== 0 + const origin = this.isDocument() ? originFromURI(this.url) : this.tabOrigin; this.setDocOrigin(origin).setTabOrigin(origin); diff --git a/src/js/benchmarks.js b/src/js/benchmarks.js index 9fdc6ec104538..59996b0f63746 100644 --- a/src/js/benchmarks.js +++ b/src/js/benchmarks.js @@ -19,26 +19,22 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - -import cosmeticFilteringEngine from './cosmetic-filtering.js'; -import io from './assets.js'; -import scriptletFilteringEngine from './scriptlet-filtering.js'; -import staticNetFilteringEngine from './static-net-filtering.js'; -import µb from './background.js'; -import webRequest from './traffic.js'; -import { FilteringContext } from './filtering-context.js'; -import { LineIterator } from './text-utils.js'; -import { sessionFirewall } from './filtering-engines.js'; - import { domainFromHostname, entityFromDomain, hostnameFromURI, } from './uri-utils.js'; +import { FilteringContext } from './filtering-context.js'; +import { LineIterator } from './text-utils.js'; +import cosmeticFilteringEngine from './cosmetic-filtering.js'; +import io from './assets.js'; +import scriptletFilteringEngine from './scriptlet-filtering.js'; +import { sessionFirewall } from './filtering-engines.js'; +import { default as sfne } from './static-net-filtering.js'; +import webRequest from './traffic.js'; +import µb from './background.js'; + /******************************************************************************/ // The requests.json.gz file can be downloaded from: @@ -134,8 +130,6 @@ const loadBenchmarkDataset = (( ) => { /******************************************************************************/ -// action: 1=test - export async function benchmarkStaticNetFiltering(options = {}) { const { target, redirectEngine } = options; @@ -155,13 +149,13 @@ export async function benchmarkStaticNetFiltering(options = {}) { fctxt.setURL(request.url); fctxt.setDocOriginFromURL(request.frameUrl); fctxt.setType(request.cpt); - const r = staticNetFilteringEngine.matchRequest(fctxt); + const r = sfne.matchRequest(fctxt); console.info(`Result=${r}:`); console.info(`\ttype=${fctxt.type}`); console.info(`\turl=${fctxt.url}`); console.info(`\tdocOrigin=${fctxt.getDocOrigin()}`); if ( r !== 0 ) { - console.info(staticNetFilteringEngine.toLogData()); + console.info(sfne.toLogData()); } return; } @@ -172,44 +166,53 @@ export async function benchmarkStaticNetFiltering(options = {}) { let allowCount = 0; let redirectCount = 0; let removeparamCount = 0; + let urlskipCount = 0; let cspCount = 0; let permissionsCount = 0; let replaceCount = 0; - for ( let i = 0; i < requests.length; i++ ) { - const request = requests[i]; + for ( const request of requests ) { fctxt.setURL(request.url); + if ( fctxt.getIPAddress() === '' ) { + fctxt.setIPAddress('93.184.215.14\n2606:2800:21f:cb07:6820:80da:af6b:8b2c'); + } fctxt.setDocOriginFromURL(request.frameUrl); fctxt.setType(request.cpt); - staticNetFilteringEngine.redirectURL = undefined; - const r = staticNetFilteringEngine.matchRequest(fctxt); + sfne.redirectURL = undefined; + const r = sfne.matchRequest(fctxt); matchCount += 1; if ( r === 1 ) { blockCount += 1; } else if ( r === 2 ) { allowCount += 1; } if ( r !== 1 ) { - if ( staticNetFilteringEngine.transformRequest(fctxt) ) { + if ( sfne.transformRequest(fctxt) ) { redirectCount += 1; } - if ( fctxt.redirectURL !== undefined && staticNetFilteringEngine.hasQuery(fctxt) ) { - if ( staticNetFilteringEngine.filterQuery(fctxt, 'removeparam') ) { + if ( sfne.hasQuery(fctxt) ) { + if ( sfne.filterQuery(fctxt) ) { removeparamCount += 1; } } - if ( fctxt.type === 'main_frame' || fctxt.type === 'sub_frame' ) { - if ( staticNetFilteringEngine.matchAndFetchModifiers(fctxt, 'csp') ) { + if ( sfne.urlSkip(fctxt, false) ) { + urlskipCount += 1; + } + if ( fctxt.isDocument() ) { + if ( sfne.matchAndFetchModifiers(fctxt, 'csp') ) { cspCount += 1; } - if ( staticNetFilteringEngine.matchAndFetchModifiers(fctxt, 'permissions') ) { + if ( sfne.matchAndFetchModifiers(fctxt, 'permissions') ) { permissionsCount += 1; } } - staticNetFilteringEngine.matchHeaders(fctxt, []); - if ( staticNetFilteringEngine.matchAndFetchModifiers(fctxt, 'replace') ) { + sfne.matchHeaders(fctxt, []); + if ( sfne.matchAndFetchModifiers(fctxt, 'replace') ) { replaceCount += 1; } } else if ( redirectEngine !== undefined ) { - if ( staticNetFilteringEngine.redirectRequest(redirectEngine, fctxt) ) { + if ( sfne.redirectRequest(redirectEngine, fctxt) ) { redirectCount += 1; } + if ( fctxt.isRootDocument() && sfne.urlSkip(fctxt, true) ) { + urlskipCount += 1; + } } } const t1 = performance.now(); @@ -217,13 +220,14 @@ export async function benchmarkStaticNetFiltering(options = {}) { const output = [ 'Benchmarked static network filtering engine:', - `\tEvaluated ${matchCount} match calls in ${dur.toFixed(0)} ms`, + `\tEvaluated ${matchCount} requests in ${dur.toFixed(0)} ms`, `\tAverage: ${(dur / matchCount).toFixed(3)} ms per request`, `\tNot blocked: ${matchCount - blockCount - allowCount}`, `\tBlocked: ${blockCount}`, `\tUnblocked: ${allowCount}`, `\tredirect=: ${redirectCount}`, `\tremoveparam=: ${removeparamCount}`, + `\turlskip=: ${urlskipCount}`, `\tcsp=: ${cspCount}`, `\tpermissions=: ${permissionsCount}`, `\treplace=: ${replaceCount}`, @@ -254,7 +258,7 @@ export async function tokenHistogramsfunction() { fctxt.setURL(request.url); fctxt.setDocOriginFromURL(request.frameUrl); fctxt.setType(request.cpt); - const r = staticNetFilteringEngine.matchRequest(fctxt); + const r = sfne.matchRequest(fctxt); for ( let [ keyword ] of request.url.toLowerCase().matchAll(reTokens) ) { const token = keyword.slice(0, 7); if ( r === 0 ) { diff --git a/src/js/biditrie.js b/src/js/biditrie.js index 06566d2e1ac98..560d5918a2276 100644 --- a/src/js/biditrie.js +++ b/src/js/biditrie.js @@ -587,7 +587,7 @@ class BidiTrieContainer { } fromSelfie(selfie) { - if ( selfie instanceof Object === false ) { return false; } + if ( typeof selfie !== 'object' || selfie === null ) { 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 --git a/src/js/codemirror/ubo-static-filtering.js b/src/js/codemirror/ubo-static-filtering.js index 2aaf85b3df6ea..386ed52f3aa93 100644 --- a/src/js/codemirror/ubo-static-filtering.js +++ b/src/js/codemirror/ubo-static-filtering.js @@ -189,6 +189,7 @@ const uBOStaticFilteringMode = (( ) => { mode.lastNetOptionType = nodeType; return 'def'; case sfp.NODE_TYPE_NET_OPTION_ASSIGN: + case sfp.NODE_TYPE_NET_OPTION_QUOTE: return 'def'; case sfp.NODE_TYPE_NET_OPTION_VALUE: if ( mode.astWalker.canGoDown() ) { break; } diff --git a/src/js/contentscript-extra.js b/src/js/contentscript-extra.js index 0c3104d91bf11..21feb1d390b32 100644 --- a/src/js/contentscript-extra.js +++ b/src/js/contentscript-extra.js @@ -173,6 +173,30 @@ class PSelectorMatchesPathTask extends PSelectorTask { } } +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(); @@ -461,6 +485,7 @@ PSelector.prototype.operatorToTaskMap = new Map([ [ 'matches-css-before', PSelectorMatchesCSSBeforeTask ], [ 'matches-media', PSelectorMatchesMediaTask ], [ 'matches-path', PSelectorMatchesPathTask ], + [ 'matches-prop', PSelectorMatchesPropTask ], [ 'min-text-length', PSelectorMinTextLengthTask ], [ 'not', PSelectorIfNotTask ], [ 'others', PSelectorOthersTask ], diff --git a/src/js/contextmenu.js b/src/js/contextmenu.js index 788b62bb35687..a2b01e9a1f9c3 100644 --- a/src/js/contextmenu.js +++ b/src/js/contextmenu.js @@ -19,12 +19,8 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - -import µb from './background.js'; import { i18n$ } from './i18n.js'; +import µb from './background.js'; /******************************************************************************/ @@ -55,18 +51,23 @@ const onBlockElement = function(details, tab) { let src = details.frameUrl || details.srcUrl || details.linkUrl || ''; if ( !tagName ) { - if ( typeof details.frameUrl === 'string' ) { + if ( typeof details.frameUrl === 'string' && details.frameId !== 0 ) { tagName = 'iframe'; + src = details.srcUrl; } else if ( typeof details.srcUrl === 'string' ) { if ( details.mediaType === 'image' ) { tagName = 'img'; + src = details.srcUrl; } else if ( details.mediaType === 'video' ) { tagName = 'video'; + src = details.srcUrl; } else if ( details.mediaType === 'audio' ) { tagName = 'audio'; + src = details.srcUrl; } } else if ( typeof details.linkUrl === 'string' ) { tagName = 'a'; + src = details.linkUrl; } } @@ -200,27 +201,25 @@ let currentBits = 0; const update = function(tabId = undefined) { let newBits = 0; - if ( - µb.userSettings.contextMenuEnabled && - µb.userFiltersAreEnabled() && - tabId !== undefined - ) { - const pageStore = µb.pageStoreFromTabId(tabId); - if ( pageStore && pageStore.getNetFilteringSwitch() ) { - if ( pageStore.shouldApplySpecificCosmeticFilters(0) ) { - newBits |= BLOCK_ELEMENT_BIT; - } else { - newBits |= BLOCK_RESOURCE_BIT; + if ( µb.userSettings.contextMenuEnabled ) { + const pageStore = tabId && µb.pageStoreFromTabId(tabId) || null; + if ( pageStore?.getNetFilteringSwitch() ) { + if ( µb.userFiltersAreEnabled() ) { + if ( pageStore.shouldApplySpecificCosmeticFilters(0) ) { + newBits |= BLOCK_ELEMENT_BIT; + } else { + newBits |= BLOCK_RESOURCE_BIT; + } } if ( pageStore.largeMediaCount !== 0 ) { newBits |= TEMP_ALLOW_LARGE_MEDIA_BIT; } } - newBits |= SUBSCRIBE_TO_LIST_BIT; - } - if ( µb.hiddenSettings.filterAuthorMode ) { - newBits |= VIEW_SOURCE_BIT; + if ( µb.hiddenSettings.filterAuthorMode ) { + newBits |= VIEW_SOURCE_BIT; + } } + newBits |= SUBSCRIBE_TO_LIST_BIT; if ( newBits === currentBits ) { return; } currentBits = newBits; const usedEntries = []; diff --git a/src/js/devtools.js b/src/js/devtools.js index 0763b0be83b6c..92cd078940f80 100644 --- a/src/js/devtools.js +++ b/src/js/devtools.js @@ -21,8 +21,7 @@ /* global CodeMirror, uBlockDashboard */ -'use strict'; - +import * as s14e from './s14e-serializer.js'; import { dom, qs$ } from './dom.js'; /******************************************************************************/ @@ -81,6 +80,100 @@ function log(text) { cmEditor.replaceRange(text.trim() + '\n\n', { line: 0, ch: 0 }); } +/******************************************************************************/ + +function toDNRText(raw) { + const result = s14e.deserialize(raw); + if ( typeof result === 'string' ) { return result; } + const { network } = result; + const replacer = (k, v) => { + if ( k.startsWith('__') ) { return; } + if ( Array.isArray(v) ) { + return v.sort(); + } + if ( v instanceof Object ) { + const sorted = {}; + for ( const kk of Object.keys(v).sort() ) { + sorted[kk] = v[kk]; + } + return sorted; + } + return v; + }; + const isUnsupported = rule => + rule._error !== undefined; + const isRegex = rule => + rule.condition !== undefined && + rule.condition.regexFilter !== undefined; + const isRedirect = rule => + rule.action !== undefined && + rule.action.type === 'redirect' && + rule.action.redirect.extensionPath !== undefined; + const isCsp = rule => + rule.action !== undefined && + rule.action.type === 'modifyHeaders'; + const isRemoveparam = rule => + rule.action !== undefined && + rule.action.type === 'redirect' && + rule.action.redirect.transform !== undefined; + const { ruleset } = network; + const good = ruleset.filter(rule => + isUnsupported(rule) === false && + isRegex(rule) === false && + isRedirect(rule) === false && + isCsp(rule) === false && + isRemoveparam(rule) === false + ); + const unsupported = ruleset.filter(rule => + isUnsupported(rule) + ); + const regexes = ruleset.filter(rule => + isUnsupported(rule) === false && + isRegex(rule) && + isRedirect(rule) === false && + isCsp(rule) === false && + isRemoveparam(rule) === false + ); + const redirects = ruleset.filter(rule => + isUnsupported(rule) === false && + isRedirect(rule) + ); + const headers = ruleset.filter(rule => + isUnsupported(rule) === false && + isCsp(rule) + ); + const removeparams = ruleset.filter(rule => + isUnsupported(rule) === false && + isRemoveparam(rule) + ); + const out = [ + `dnrRulesetFromRawLists(${JSON.stringify(result.listNames, null, 2)})`, + `Run time: ${result.runtime} ms`, + `Filters count: ${network.filterCount}`, + `Accepted filter count: ${network.acceptedFilterCount}`, + `Rejected filter count: ${network.rejectedFilterCount}`, + `Un-DNR-able filter count: ${unsupported.length}`, + `Resulting DNR rule count: ${ruleset.length}`, + ]; + out.push(`+ Good filters (${good.length}): ${JSON.stringify(good, replacer, 2)}`); + out.push(`+ Regex-based filters (${regexes.length}): ${JSON.stringify(regexes, replacer, 2)}`); + out.push(`+ 'redirect=' filters (${redirects.length}): ${JSON.stringify(redirects, replacer, 2)}`); + out.push(`+ 'csp=' filters (${headers.length}): ${JSON.stringify(headers, replacer, 2)}`); + out.push(`+ 'removeparam=' filters (${removeparams.length}): ${JSON.stringify(removeparams, replacer, 2)}`); + out.push(`+ Unsupported filters (${unsupported.length}): ${JSON.stringify(unsupported, replacer, 2)}`); + out.push(`+ generichide exclusions (${network.generichideExclusions.length}): ${JSON.stringify(network.generichideExclusions, replacer, 2)}`); + if ( result.specificCosmetic ) { + out.push(`+ Cosmetic filters: ${result.specificCosmetic.size}`); + for ( const details of result.specificCosmetic ) { + out.push(` ${JSON.stringify(details)}`); + } + } else { + out.push(' Cosmetic filters: 0'); + } + return out.join('\n'); +} + + /******************************************************************************/ dom.on('#console-clear', 'click', ( ) => { @@ -148,7 +241,7 @@ dom.on('#snfe-todnr', 'click', ev => { vAPI.messaging.send('devTools', { what: 'snfeToDNR', }).then(result => { - log(result); + log(toDNRText(result)); dom.attr(button, 'disabled', null); }); }); @@ -212,3 +305,44 @@ vAPI.messaging.send('dashboard', { }); /******************************************************************************/ + +async function snfeQuery(lineNo, query) { + const doc = cmEditor.getDoc(); + const lineHandle = doc.getLineHandle(lineNo) + const result = await vAPI.messaging.send('devTools', { + what: 'snfeQuery', + query + }); + if ( typeof result !== 'string' ) { return; } + cmEditor.startOperation(); + const nextLineNo = doc.getLineNumber(lineHandle) + 1; + doc.replaceRange(`${result}\n`, { line: nextLineNo, ch: 0 }); + cmEditor.endOperation(); +} + +cmEditor.on('beforeChange', (cm, details) => { + if ( details.origin !== '+input' ) { return; } + if ( details.text.length !== 2 ) { return; } + if ( details.text[1] !== '' ) { return; } + const lineNo = details.from.line; + const line = cm.getLine(lineNo); + if ( details.from.ch !== line.length ) { return; } + if ( line.startsWith('snfe?') === false ) { return; } + const fields = line.slice(5).split(/\s+/); + const query = {}; + for ( const field of fields ) { + if ( /[/.]/.test(field) ) { + if ( query.url === undefined ) { + query.url = field; + } else if ( query.from === undefined ) { + query.from = field; + } + } else if ( query.type === undefined ) { + query.type = field; + } + } + if ( query.url === undefined ) { return; } + snfeQuery(lineNo, query); +}); + +/******************************************************************************/ diff --git a/src/js/document-blocked.js b/src/js/document-blocked.js index 59a6bc85a3533..0bccb06a208e8 100644 --- a/src/js/document-blocked.js +++ b/src/js/document-blocked.js @@ -19,10 +19,8 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -import { i18n, i18n$ } from './i18n.js'; import { dom, qs$ } from './dom.js'; +import { i18n, i18n$ } from './i18n.js'; /******************************************************************************/ @@ -47,7 +45,7 @@ let details = {}; let lists; for ( const rawFilter in response ) { - if ( response.hasOwnProperty(rawFilter) ) { + if ( Object.prototype.hasOwnProperty.call(response, rawFilter) ) { lists = response[rawFilter]; break; } @@ -77,9 +75,47 @@ let details = {}; /******************************************************************************/ -dom.text('#theURL > p > span:first-of-type', details.url); +const urlToFragment = raw => { + try { + const fragment = new DocumentFragment(); + const url = new URL(raw); + const hn = url.hostname; + const i = raw.indexOf(hn); + const b = document.createElement('b'); + b.append(hn); + fragment.append(raw.slice(0,i), b, raw.slice(i+hn.length)); + return fragment; + } catch(_) { + } + return raw; +}; + +/******************************************************************************/ + +dom.clear('#theURL > p > span:first-of-type'); +qs$('#theURL > p > span:first-of-type').append(urlToFragment(details.url)); dom.text('#why', details.fs); +if ( typeof details.to === 'string' && details.to.length !== 0 ) { + const fragment = new DocumentFragment(); + const text = i18n$('docblockedRedirectPrompt'); + const linkPlaceholder = '{{url}}'; + let pos = text.indexOf(linkPlaceholder); + if ( pos !== -1 ) { + const link = document.createElement('a'); + link.href = details.to; + dom.cl.add(link, 'code'); + link.append(urlToFragment(details.to)); + fragment.append( + text.slice(0, pos), + link, + text.slice(pos + linkPlaceholder.length) + ); + qs$('#urlskip').append(fragment); + dom.attr('#urlskip', 'hidden', null); + } +} + /******************************************************************************/ // https://github.com/gorhill/uBlock/issues/691 diff --git a/src/js/dom.js b/src/js/dom.js index 5c4d19479f80d..241af9d525b1b 100644 --- a/src/js/dom.js +++ b/src/js/dom.js @@ -19,10 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - /******************************************************************************/ const normalizeTarget = target => { @@ -113,6 +109,14 @@ class dom { } } + static empty(target) { + for ( const elem of normalizeTarget(target) ) { + while ( elem.firstElementChild !== null ) { + elem.firstElementChild.remove(); + } + } + } + // target, type, callback, [options] // target, type, subtarget, callback, [options] diff --git a/src/js/epicker-ui.js b/src/js/epicker-ui.js index 981602b66f354..d2b14df65dce0 100644 --- a/src/js/epicker-ui.js +++ b/src/js/epicker-ui.js @@ -386,7 +386,7 @@ const onSvgTouch = (( ) => { const stopY = ev.changedTouches[0].screenY; const angle = Math.abs(Math.atan2(stopY - startY, stopX - startX)); const distance = Math.sqrt( - Math.pow(stopX - startX, 2), + Math.pow(stopX - startX, 2) + Math.pow(stopY - startY, 2) ); // Interpret touch events as a tap if: diff --git a/src/js/filtering-context.js b/src/js/filtering-context.js index 6642050712904..a24cdabc5da0b 100644 --- a/src/js/filtering-context.js +++ b/src/js/filtering-context.js @@ -19,13 +19,9 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - import { - hostnameFromURI, domainFromHostname, + hostnameFromURI, originFromURI, } from './uri-utils.js'; @@ -56,7 +52,7 @@ export const XMLHTTPREQUEST = 1 << 13; export const INLINE_FONT = 1 << 14; export const INLINE_SCRIPT = 1 << 15; export const OTHER = 1 << 16; -export const FRAME_ANY = MAIN_FRAME | SUB_FRAME; +export const FRAME_ANY = MAIN_FRAME | SUB_FRAME | OBJECT; export const FONT_ANY = FONT | INLINE_FONT; export const INLINE_ANY = INLINE_FONT | INLINE_SCRIPT; export const PING_ANY = BEACON | CSP_REPORT | PING; @@ -126,6 +122,8 @@ const methodBitToStrMap = new Map([ [ METHOD_PUT, 'put' ], ]); +const reIPv4 = /^\d+\.\d+\.\d+\.\d+$/; + /******************************************************************************/ export const FilteringContext = class { @@ -142,6 +140,7 @@ export const FilteringContext = class { this.aliasURL = undefined; this.hostname = undefined; this.domain = undefined; + this.ipaddress = undefined; this.docId = -1; this.frameId = -1; this.docOrigin = undefined; @@ -164,6 +163,9 @@ export const FilteringContext = class { this.stype = a; } + isRootDocument() { + return (this.itype & MAIN_FRAME) !== 0; + } isDocument() { return (this.itype & FRAME_ANY) !== 0; } @@ -179,6 +181,7 @@ export const FilteringContext = class { this.url = other.url; this.hostname = other.hostname; this.domain = other.domain; + this.ipaddress = other.ipaddress; this.docId = other.docId; this.frameId = other.frameId; this.docOrigin = other.docOrigin; @@ -216,7 +219,7 @@ export const FilteringContext = class { setURL(a) { if ( a !== this.url ) { - this.hostname = this.domain = undefined; + this.hostname = this.domain = this.ipaddress = undefined; this.url = a; } return this; @@ -249,6 +252,28 @@ export const FilteringContext = class { return this; } + getIPAddress() { + if ( this.ipaddress !== undefined ) { + return this.ipaddress; + } + const ipaddr = this.getHostname(); + const c0 = ipaddr.charCodeAt(0); + if ( c0 === 0x5B /* [ */ ) { + return (this.ipaddress = ipaddr.slice(1, -1)); + } else if ( c0 <= 0x39 && c0 >= 0x30 ) { + if ( reIPv4.test(ipaddr) ) { + return (this.ipaddress = ipaddr); + } + } + return (this.ipaddress = ''); + } + + // Must always be called *after* setURL() + setIPAddress(ipaddr) { + this.ipaddress = ipaddr || undefined; + return this; + } + getDocOrigin() { if ( this.docOrigin === undefined ) { this.docOrigin = this.tabOrigin; @@ -418,42 +443,72 @@ export const FilteringContext = class { static getMethodName(a) { return methodBitToStrMap.get(a) || ''; } -}; - -/******************************************************************************/ -FilteringContext.prototype.BEACON = FilteringContext.BEACON = BEACON; -FilteringContext.prototype.CSP_REPORT = FilteringContext.CSP_REPORT = CSP_REPORT; -FilteringContext.prototype.FONT = FilteringContext.FONT = FONT; -FilteringContext.prototype.IMAGE = FilteringContext.IMAGE = IMAGE; -FilteringContext.prototype.IMAGESET = FilteringContext.IMAGESET = IMAGESET; -FilteringContext.prototype.MAIN_FRAME = FilteringContext.MAIN_FRAME = MAIN_FRAME; -FilteringContext.prototype.MEDIA = FilteringContext.MEDIA = MEDIA; -FilteringContext.prototype.OBJECT = FilteringContext.OBJECT = OBJECT; -FilteringContext.prototype.OBJECT_SUBREQUEST = FilteringContext.OBJECT_SUBREQUEST = OBJECT_SUBREQUEST; -FilteringContext.prototype.PING = FilteringContext.PING = PING; -FilteringContext.prototype.SCRIPT = FilteringContext.SCRIPT = SCRIPT; -FilteringContext.prototype.STYLESHEET = FilteringContext.STYLESHEET = STYLESHEET; -FilteringContext.prototype.SUB_FRAME = FilteringContext.SUB_FRAME = SUB_FRAME; -FilteringContext.prototype.WEBSOCKET = FilteringContext.WEBSOCKET = WEBSOCKET; -FilteringContext.prototype.XMLHTTPREQUEST = FilteringContext.XMLHTTPREQUEST = XMLHTTPREQUEST; -FilteringContext.prototype.INLINE_FONT = FilteringContext.INLINE_FONT = INLINE_FONT; -FilteringContext.prototype.INLINE_SCRIPT = FilteringContext.INLINE_SCRIPT = INLINE_SCRIPT; -FilteringContext.prototype.OTHER = FilteringContext.OTHER = OTHER; -FilteringContext.prototype.FRAME_ANY = FilteringContext.FRAME_ANY = FRAME_ANY; -FilteringContext.prototype.FONT_ANY = FilteringContext.FONT_ANY = FONT_ANY; -FilteringContext.prototype.INLINE_ANY = FilteringContext.INLINE_ANY = INLINE_ANY; -FilteringContext.prototype.PING_ANY = FilteringContext.PING_ANY = PING_ANY; -FilteringContext.prototype.SCRIPT_ANY = FilteringContext.SCRIPT_ANY = SCRIPT_ANY; - -FilteringContext.prototype.METHOD_NONE = FilteringContext.METHOD_NONE = METHOD_NONE; -FilteringContext.prototype.METHOD_CONNECT = FilteringContext.METHOD_CONNECT = METHOD_CONNECT; -FilteringContext.prototype.METHOD_DELETE = FilteringContext.METHOD_DELETE = METHOD_DELETE; -FilteringContext.prototype.METHOD_GET = FilteringContext.METHOD_GET = METHOD_GET; -FilteringContext.prototype.METHOD_HEAD = FilteringContext.METHOD_HEAD = METHOD_HEAD; -FilteringContext.prototype.METHOD_OPTIONS = FilteringContext.METHOD_OPTIONS = METHOD_OPTIONS; -FilteringContext.prototype.METHOD_PATCH = FilteringContext.METHOD_PATCH = METHOD_PATCH; -FilteringContext.prototype.METHOD_POST = FilteringContext.METHOD_POST = METHOD_POST; -FilteringContext.prototype.METHOD_PUT = FilteringContext.METHOD_PUT = METHOD_PUT; + BEACON = BEACON; + CSP_REPORT = CSP_REPORT; + FONT = FONT; + IMAGE = IMAGE; + IMAGESET = IMAGESET; + MAIN_FRAME = MAIN_FRAME; + MEDIA = MEDIA; + OBJECT = OBJECT; + OBJECT_SUBREQUEST = OBJECT_SUBREQUEST; + PING = PING; + SCRIPT = SCRIPT; + STYLESHEET = STYLESHEET; + SUB_FRAME = SUB_FRAME; + WEBSOCKET = WEBSOCKET; + XMLHTTPREQUEST = XMLHTTPREQUEST; + INLINE_FONT = INLINE_FONT; + INLINE_SCRIPT = INLINE_SCRIPT; + OTHER = OTHER; + FRAME_ANY = FRAME_ANY; + FONT_ANY = FONT_ANY; + INLINE_ANY = INLINE_ANY; + PING_ANY = PING_ANY; + SCRIPT_ANY = SCRIPT_ANY; + METHOD_NONE = METHOD_NONE; + METHOD_CONNECT = METHOD_CONNECT; + METHOD_DELETE = METHOD_DELETE; + METHOD_GET = METHOD_GET; + METHOD_HEAD = METHOD_HEAD; + METHOD_OPTIONS = METHOD_OPTIONS; + METHOD_PATCH = METHOD_PATCH; + METHOD_POST = METHOD_POST; + METHOD_PUT = METHOD_PUT; + + static BEACON = BEACON; + static CSP_REPORT = CSP_REPORT; + static FONT = FONT; + static IMAGE = IMAGE; + static IMAGESET = IMAGESET; + static MAIN_FRAME = MAIN_FRAME; + static MEDIA = MEDIA; + static OBJECT = OBJECT; + static OBJECT_SUBREQUEST = OBJECT_SUBREQUEST; + static PING = PING; + static SCRIPT = SCRIPT; + static STYLESHEET = STYLESHEET; + static SUB_FRAME = SUB_FRAME; + static WEBSOCKET = WEBSOCKET; + static XMLHTTPREQUEST = XMLHTTPREQUEST; + static INLINE_FONT = INLINE_FONT; + static INLINE_SCRIPT = INLINE_SCRIPT; + static OTHER = OTHER; + static FRAME_ANY = FRAME_ANY; + static FONT_ANY = FONT_ANY; + static INLINE_ANY = INLINE_ANY; + static PING_ANY = PING_ANY; + static SCRIPT_ANY = SCRIPT_ANY; + static METHOD_NONE = METHOD_NONE; + static METHOD_CONNECT = METHOD_CONNECT; + static METHOD_DELETE = METHOD_DELETE; + static METHOD_GET = METHOD_GET; + static METHOD_HEAD = METHOD_HEAD; + static METHOD_OPTIONS = METHOD_OPTIONS; + static METHOD_PATCH = METHOD_PATCH; + static METHOD_POST = METHOD_POST; + static METHOD_PUT = METHOD_PUT; +}; /******************************************************************************/ diff --git a/src/js/hntrie.js b/src/js/hntrie.js index 4f89a99642633..518d0b8ddb19c 100644 --- a/src/js/hntrie.js +++ b/src/js/hntrie.js @@ -457,7 +457,7 @@ class HNTrieContainer { } fromSelfie(selfie) { - if ( selfie instanceof Object === false ) { return false; } + if ( typeof selfie !== 'object' || selfie === null ) { return false; } if ( selfie.buf32 instanceof Uint32Array === false ) { return false; } if ( selfie.checksum !== i32Checksum(selfie.buf32) ) { return false; } this.needle = ''; diff --git a/src/js/i18n.js b/src/js/i18n.js index 18c7e1456cd43..6ce3b5f96284c 100644 --- a/src/js/i18n.js +++ b/src/js/i18n.js @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ const i18n = @@ -168,14 +166,14 @@ if ( isBackgroundProcess !== true ) { const re = /\{\{\w+\}\}/g; let textout = ''; for (;;) { - let match = re.exec(textin); + const match = re.exec(textin); if ( match === null ) { textout += textin; break; } textout += textin.slice(0, match.index); let prop = match[0].slice(2, -2); - if ( dict.hasOwnProperty(prop) ) { + if ( Object.prototype.hasOwnProperty.call(dict, prop) ) { textout += dict[prop].replace(//g, '>'); } else { diff --git a/src/js/logger-ui.js b/src/js/logger-ui.js index db95f2e114aba..0b9c31dd99d57 100644 --- a/src/js/logger-ui.js +++ b/src/js/logger-ui.js @@ -331,7 +331,7 @@ const processLoggerEntries = function(response) { parsed.type === 'main_frame' && parsed.aliased === false && ( parsed.filter === undefined || - parsed.filter.modifier !== true + parsed.filter.modifier !== true && parsed.filter.source !== 'redirect' ) ) { const separator = createLogSeparator(parsed, unboxed.url); @@ -2779,7 +2779,7 @@ const loggerStats = (( ) => { const outputOne = []; for ( let i = 0; i < fields.length; i++ ) { const field = fields[i]; - let code = /\b(?:www\.|https?:\/\/)/.test(field) ? '`' : ''; + const code = i === 1 || /\b(?:www\.|https?:\/\/)/.test(field) ? '`' : ''; outputOne.push(` ${code}${field.replace(/\|/g, '\\|')}${code} `); } outputAll.push(outputOne.join('|')); diff --git a/src/js/messaging.js b/src/js/messaging.js index 5f39af4f441dd..b24a9a5a27560 100644 --- a/src/js/messaging.js +++ b/src/js/messaging.js @@ -19,53 +19,49 @@ Home: https://github.com/gorhill/uBlock */ -/* globals browser */ - -'use strict'; +import * as s14e from './s14e-serializer.js'; +import * as sfp from './static-filtering-parser.js'; -/******************************************************************************/ +import { + domainFromHostname, + domainFromURI, + entityFromDomain, + hostnameFromURI, + isNetworkURI, +} from './uri-utils.js'; -import publicSuffixList from '../lib/publicsuffixlist/publicsuffixlist.js'; -import punycode from '../lib/punycode.js'; +import { + permanentFirewall, + permanentSwitches, + permanentURLFiltering, + sessionFirewall, + sessionSwitches, + sessionURLFiltering, +} from './filtering-engines.js'; -import { filteringBehaviorChanged } from './broadcast.js'; import cacheStorage from './cachestorage.js'; import cosmeticFilteringEngine from './cosmetic-filtering.js'; +import { denseBase64 } from './base64-custom.js'; +import { filteringBehaviorChanged } from './broadcast.js'; import htmlFilteringEngine from './html-filtering.js'; +import { i18n$ } from './i18n.js'; +import io from './assets.js'; import logger from './logger.js'; import lz4Codec from './lz4.js'; -import io from './assets.js'; +import publicSuffixList from '../lib/publicsuffixlist/publicsuffixlist.js'; +import punycode from '../lib/punycode.js'; +import { redirectEngine } from './redirect-engine.js'; import scriptletFilteringEngine from './scriptlet-filtering.js'; import staticFilteringReverseLookup from './reverselookup.js'; import staticNetFilteringEngine from './static-net-filtering.js'; -import µb from './background.js'; import webRequest from './traffic.js'; -import { denseBase64 } from './base64-custom.js'; -import { dnrRulesetFromRawLists } from './static-dnr-filtering.js'; -import { i18n$ } from './i18n.js'; -import { redirectEngine } from './redirect-engine.js'; -import * as sfp from './static-filtering-parser.js'; -import * as s14e from './s14e-serializer.js'; - -import { - permanentFirewall, - sessionFirewall, - permanentSwitches, - sessionSwitches, - permanentURLFiltering, - sessionURLFiltering, -} from './filtering-engines.js'; - -import { - domainFromHostname, - domainFromURI, - entityFromDomain, - hostnameFromURI, - isNetworkURI, -} from './uri-utils.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". @@ -291,9 +287,8 @@ const getHostnameDict = function(hostnameDetailsMap, out) { const cnMap = []; const createDictEntry = (domain, hostname, details) => { - const cname = vAPI.net.canonicalNameFromHostname(hostname); - if ( cname !== undefined ) { - cnMap.push([ cname, hostname ]); + if ( details.cname ) { + cnMap.push([ details.cname, hostname ]); } hnDict[hostname] = { domain, counts: details.counts }; }; @@ -807,8 +802,11 @@ const onMessage = function(request, sender, callback) { }); break; - case 'shouldRenderNoscriptTags': + case 'shouldRenderNoscriptTags': { if ( pageStore === null ) { break; } + if ( µb.hiddenSettings.noScriptingCSP !== µb.hiddenSettingsDefault.noScriptingCSP ) { + break; + } const fctxt = µb.filteringContext.fromTabId(sender.tabId); if ( pageStore.filterScripting(fctxt, undefined) ) { vAPI.tabs.executeScript(sender.tabId, { @@ -818,7 +816,7 @@ const onMessage = function(request, sender, callback) { }); } break; - + } case 'retrieveGenericCosmeticSelectors': request.tabId = sender.tabId; request.frameId = sender.frameId; @@ -1098,7 +1096,7 @@ const restoreUserData = async function(request) { // Discard unknown setting or setting with default value. for ( const key in hiddenSettings ) { if ( - µb.hiddenSettingsDefault.hasOwnProperty(key) === false || + hasOwnProperty(µb.hiddenSettingsDefault, key) === false || hiddenSettings[key] === µb.hiddenSettingsDefault[key] ) { delete hiddenSettings[key]; @@ -1128,7 +1126,7 @@ const restoreUserData = async function(request) { }); µb.saveUserFilters(userData.userFilters); if ( Array.isArray(userData.selectedFilterLists) ) { - await µb.saveSelectedFilterLists(userData.selectedFilterLists); + await µb.saveSelectedFilterLists(userData.selectedFilterLists); } vAPI.app.restart(); @@ -1150,7 +1148,7 @@ const resetUserData = async function() { // Filter lists const prepListEntries = function(entries) { for ( const k in entries ) { - if ( entries.hasOwnProperty(k) === false ) { continue; } + if ( hasOwnProperty(entries, k) === false ) { continue; } const entry = entries[k]; if ( typeof entry.supportURL === 'string' && entry.supportURL !== '' ) { entry.supportName = hostnameFromURI(entry.supportURL); @@ -1338,7 +1336,7 @@ const getSupportData = async function() { let addedListset = {}; let removedListset = {}; for ( const listKey in lists ) { - if ( lists.hasOwnProperty(listKey) === false ) { continue; } + if ( hasOwnProperty(lists, listKey) === false ) { continue; } const list = lists[listKey]; if ( list.content !== 'filters' ) { continue; } const used = µb.selectedFilterLists.includes(listKey); @@ -1755,7 +1753,7 @@ const onMessage = (request, sender, callback) => { // Sync let response; switch ( request.what ) { - case 'getInspectorArgs': + case 'getInspectorArgs': { const bc = new globalThis.BroadcastChannel('contentInspectorChannel'); bc.postMessage({ what: 'contentInspectorChannel', @@ -1768,6 +1766,7 @@ const onMessage = (request, sender, callback) => { ), }; break; + } default: return vAPI.messaging.UNHANDLED; } @@ -1888,7 +1887,11 @@ const onMessage = function(request, sender, callback) { listPromises.push( io.get(assetKey, { dontCache: true }).then(details => { listNames.push(assetKey); - return { name: assetKey, text: details.content }; + return { + name: assetKey, + text: details.content, + trustedSource: assetKey.startsWith('ublock-'), + }; }) ); } @@ -1900,95 +1903,15 @@ const onMessage = function(request, sender, callback) { ), env: vAPI.webextFlavor.env, }; - const t0 = Date.now(); - dnrRulesetFromRawLists(listPromises, options).then(result => { - const { network } = result; - const replacer = (k, v) => { - if ( k.startsWith('__') ) { return; } - if ( Array.isArray(v) ) { - return v.sort(); - } - if ( v instanceof Object ) { - const sorted = {}; - for ( const kk of Object.keys(v).sort() ) { - sorted[kk] = v[kk]; - } - return sorted; - } - return v; - }; - const isUnsupported = rule => - rule._error !== undefined; - const isRegex = rule => - rule.condition !== undefined && - rule.condition.regexFilter !== undefined; - const isRedirect = rule => - rule.action !== undefined && - rule.action.type === 'redirect' && - rule.action.redirect.extensionPath !== undefined; - const isCsp = rule => - rule.action !== undefined && - rule.action.type === 'modifyHeaders'; - const isRemoveparam = rule => - rule.action !== undefined && - rule.action.type === 'redirect' && - rule.action.redirect.transform !== undefined; - const runtime = Date.now() - t0; - const { ruleset } = network; - const good = ruleset.filter(rule => - isUnsupported(rule) === false && - isRegex(rule) === false && - isRedirect(rule) === false && - isCsp(rule) === false && - isRemoveparam(rule) === false - ); - const unsupported = ruleset.filter(rule => - isUnsupported(rule) - ); - const regexes = ruleset.filter(rule => - isUnsupported(rule) === false && - isRegex(rule) && - isRedirect(rule) === false && - isCsp(rule) === false && - isRemoveparam(rule) === false - ); - const redirects = ruleset.filter(rule => - isUnsupported(rule) === false && - isRedirect(rule) - ); - const headers = ruleset.filter(rule => - isUnsupported(rule) === false && - isCsp(rule) - ); - const removeparams = ruleset.filter(rule => - isUnsupported(rule) === false && - isRemoveparam(rule) - ); - const out = [ - `dnrRulesetFromRawLists(${JSON.stringify(listNames, null, 2)})`, - `Run time: ${runtime} ms`, - `Filters count: ${network.filterCount}`, - `Accepted filter count: ${network.acceptedFilterCount}`, - `Rejected filter count: ${network.rejectedFilterCount}`, - `Un-DNR-able filter count: ${unsupported.length}`, - `Resulting DNR rule count: ${ruleset.length}`, - ]; - out.push(`+ Good filters (${good.length}): ${JSON.stringify(good, replacer, 2)}`); - out.push(`+ Regex-based filters (${regexes.length}): ${JSON.stringify(regexes, replacer, 2)}`); - out.push(`+ 'redirect=' filters (${redirects.length}): ${JSON.stringify(redirects, replacer, 2)}`); - out.push(`+ 'csp=' filters (${headers.length}): ${JSON.stringify(headers, replacer, 2)}`); - out.push(`+ 'removeparam=' filters (${removeparams.length}): ${JSON.stringify(removeparams, replacer, 2)}`); - out.push(`+ Unsupported filters (${unsupported.length}): ${JSON.stringify(unsupported, replacer, 2)}`); - out.push(`+ generichide exclusions (${network.generichideExclusions.length}): ${JSON.stringify(network.generichideExclusions, replacer, 2)}`); - if ( result.specificCosmetic ) { - out.push(`+ Cosmetic filters: ${result.specificCosmetic.size}`); - for ( const details of result.specificCosmetic ) { - out.push(` ${JSON.stringify(details)}`); - } - } else { - out.push(' Cosmetic filters: 0'); - } - callback(out.join('\n')); + import('./static-dnr-filtering.js').then(module => { + const t0 = Date.now(); + module.dnrRulesetFromRawLists(listPromises, options).then(dnrdata => { + dnrdata.listNames = listNames; + dnrdata.runtime = Date.now() - t0; + callback(s14e.serialize(dnrdata)); + }) + }).catch(reason => { + callback(reason); }); return; } @@ -2004,6 +1927,12 @@ const onMessage = function(request, sender, callback) { response = staticNetFilteringEngine.dump(); break; + case 'snfeQuery': + response = staticNetFilteringEngine.test( + Object.assign({ redirectEngine }, request.query) + ); + break; + case 'cfeDump': response = cosmeticFilteringEngine.dump(); break; @@ -2087,7 +2016,7 @@ const logCSPViolations = function(pageStore, request) { fctxt.type = 'script'; fctxt.filter = undefined; if ( pageStore.filterScripting(fctxt, true) === 1 ) { - cspData.set(µb.cspNoScripting, fctxt.filter); + cspData.set(µb.hiddenSettings.noScriptingCSP, fctxt.filter); } fctxt.type = 'inline-font'; @@ -2181,7 +2110,7 @@ const onMessage = function(request, sender, callback) { } break; - case 'subscribeTo': + case 'subscribeTo': { // https://github.com/uBlockOrigin/uBlock-issues/issues/1797 if ( /^(file|https?):\/\//.test(request.location) === false ) { break; } const url = encodeURIComponent(request.location); @@ -2194,8 +2123,8 @@ const onMessage = function(request, sender, callback) { select: true, }); break; - - case 'updateLists': + } + case 'updateLists': { const listkeys = request.listkeys.split(',').filter(s => s !== ''); if ( listkeys.length === 0 ) { return; } if ( listkeys.includes('all') ) { @@ -2211,7 +2140,7 @@ const onMessage = function(request, sender, callback) { }); µb.scheduleAssetUpdater({ now: true, fetchDelay: 100, auto: request.auto }); break; - + } default: return vAPI.messaging.UNHANDLED; } diff --git a/src/js/pagestore.js b/src/js/pagestore.js index 227352d5d97e6..7adca8482847e 100644 --- a/src/js/pagestore.js +++ b/src/js/pagestore.js @@ -53,6 +53,9 @@ To create a log of net requests /******************************************************************************/ const NetFilteringResultCache = class { + shelfLife = 15000; + extensionOriginURL = vAPI.getURL('/'); + constructor() { this.pruneTimer = vAPI.defer.create(( ) => { this.prune(); @@ -172,9 +175,6 @@ const NetFilteringResultCache = class { } }; -NetFilteringResultCache.prototype.shelfLife = 15000; -NetFilteringResultCache.prototype.extensionOriginURL = vAPI.getURL('/'); - /******************************************************************************/ // Frame stores are used solely to associate a URL with a frame id. @@ -274,18 +274,16 @@ const FrameStore = class { } static factory(frameURL, parentId = -1) { - const entry = FrameStore.junkyard.pop(); - if ( entry === undefined ) { - return new FrameStore(frameURL, parentId); + const FS = FrameStore; + if ( FS.junkyard.length !== 0 ) { + return FS.junkyard.pop().init(frameURL, parentId); } - return entry.init(frameURL, parentId); + return new FS(frameURL, parentId); } + static junkyard = []; + static junkyardMax = 50; }; -// To mitigate memory churning -FrameStore.junkyard = []; -FrameStore.junkyardMax = 50; - /******************************************************************************/ const CountDetails = class { @@ -312,19 +310,26 @@ const HostnameDetails = class { } init(hostname) { this.hostname = hostname; + this.cname = vAPI.net.canonicalNameFromHostname(hostname); this.counts.reset(); + return this; } dispose() { - this.hostname = ''; - if ( HostnameDetails.junkyard.length < HostnameDetails.junkyardMax ) { - HostnameDetails.junkyard.push(this); + const HD = HostnameDetails; + if ( HD.junkyard.length >= HD.junkyardMax ) { return; } + HD.junkyard.push(this); + } + static factory(hostname) { + const HD = HostnameDetails; + if ( HD.junkyard.length !== 0 ) { + return HD.junkyard.pop().init(hostname); } + return new HD(hostname); } + static junkyard = []; + static junkyardMax = 100; }; -HostnameDetails.junkyard = []; -HostnameDetails.junkyardMax = 100; - const HostnameDetailsMap = class extends Map { reset() { this.clear(); @@ -622,7 +627,7 @@ const PageStore = class { ) { this.hostnameDetailsMap.set( this.tabHostname, - new HostnameDetails(this.tabHostname) + HostnameDetails.factory(this.tabHostname) ); } return this.hostnameDetailsMap; @@ -700,7 +705,7 @@ const PageStore = class { const hostname = journal[i+0]; let hnDetails = this.hostnameDetailsMap.get(hostname); if ( hnDetails === undefined ) { - hnDetails = new HostnameDetails(hostname); + hnDetails = HostnameDetails.factory(hostname); this.hostnameDetailsMap.set(hostname, hnDetails); this.contentLastModified = now; } @@ -920,8 +925,11 @@ const PageStore = class { } redirectBlockedRequest(fctxt) { - const directives = staticNetFilteringEngine.redirectRequest(redirectEngine, fctxt); - if ( directives === undefined ) { return; } + const directives = staticNetFilteringEngine.redirectRequest(redirectEngine, fctxt) || []; + if ( this.urlSkippableResources.has(fctxt.itype) ) { + staticNetFilteringEngine.urlSkip(fctxt, true, directives); + } + if ( directives.length === 0 ) { return; } if ( logger.enabled !== true ) { return; } fctxt.pushFilters(directives.map(a => a.logData())); if ( fctxt.redirectURL === undefined ) { return; } @@ -932,19 +940,17 @@ const PageStore = class { } redirectNonBlockedRequest(fctxt) { - const transformDirectives = staticNetFilteringEngine.transformRequest(fctxt); - const pruneDirectives = fctxt.redirectURL === undefined && - staticNetFilteringEngine.hasQuery(fctxt) && - staticNetFilteringEngine.filterQuery(fctxt) || - undefined; - if ( transformDirectives === undefined && pruneDirectives === undefined ) { return; } - if ( logger.enabled !== true ) { return; } - if ( transformDirectives !== undefined ) { - fctxt.pushFilters(transformDirectives.map(a => a.logData())); + const directives = []; + staticNetFilteringEngine.transformRequest(fctxt, directives); + if ( staticNetFilteringEngine.hasQuery(fctxt) ) { + staticNetFilteringEngine.filterQuery(fctxt, directives); } - if ( pruneDirectives !== undefined ) { - fctxt.pushFilters(pruneDirectives.map(a => a.logData())); + if ( this.urlSkippableResources.has(fctxt.itype) ) { + staticNetFilteringEngine.urlSkip(fctxt, false, directives); } + if ( directives.length === 0 ) { return; } + if ( logger.enabled !== true ) { return; } + fctxt.pushFilters(directives.map(a => a.logData())); if ( fctxt.redirectURL === undefined ) { return; } fctxt.pushFilter({ source: 'redirect', @@ -952,6 +958,19 @@ const PageStore = class { }); } + 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 + }); + } + } + filterCSPReport(fctxt) { if ( sessionSwitches.evaluateZ( @@ -1006,48 +1025,53 @@ const PageStore = class { } // The caller is responsible to check whether filtering is enabled or not. - filterLargeMediaElement(fctxt, size) { + filterLargeMediaElement(fctxt, headers) { fctxt.filter = undefined; - - if ( this.allowLargeMediaElementsUntil === 0 ) { + if ( this.allowLargeMediaElementsUntil === 0 ) { return 0; } + if ( sessionSwitches.evaluateZ('no-large-media', fctxt.getTabHostname() ) !== true ) { + this.allowLargeMediaElementsUntil = 0; return 0; } - // Disregard large media elements previously allowed: for example, to - // seek inside a previously allowed audio/video. - if ( - this.allowLargeMediaElementsRegex instanceof RegExp && - this.allowLargeMediaElementsRegex.test(fctxt.url) - ) { + // XHR-based streaming is never blocked but we want to prevent autoplay + if ( fctxt.itype === fctxt.XMLHTTPREQUEST ) { + const ctype = headers.contentType; + if ( ctype.startsWith('audio/') || ctype.startsWith('video/') ) { + this.largeMediaTimer.on(500); + } return 0; } if ( Date.now() < this.allowLargeMediaElementsUntil ) { - const sources = this.allowLargeMediaElementsRegex instanceof RegExp - ? [ this.allowLargeMediaElementsRegex.source ] - : []; - sources.push('^' + µb.escapeRegex(fctxt.url)); - this.allowLargeMediaElementsRegex = new RegExp(sources.join('|')); + if ( fctxt.itype === fctxt.MEDIA ) { + const sources = this.allowLargeMediaElementsRegex instanceof RegExp + ? [ this.allowLargeMediaElementsRegex.source ] + : []; + sources.push('^' + µb.escapeRegex(fctxt.url)); + this.allowLargeMediaElementsRegex = new RegExp(sources.join('|')); + } return 0; } + // Disregard large media elements previously allowed: for example, to + // seek inside a previously allowed audio/video. if ( - sessionSwitches.evaluateZ( - 'no-large-media', - fctxt.getTabHostname() - ) !== true + this.allowLargeMediaElementsRegex instanceof RegExp && + this.allowLargeMediaElementsRegex.test(fctxt.url) ) { - this.allowLargeMediaElementsUntil = 0; return 0; } - if ( (size >>> 10) < µb.userSettings.largeMediaSize ) { - return 0; + // Regardless of whether a media is blocked, we want to prevent autoplay + if ( fctxt.itype === fctxt.MEDIA ) { + this.largeMediaTimer.on(500); } - + const size = headers.contentLength; + if ( isNaN(size) ) { + return µb.userSettings.largeMediaSize === 0 ? 1 : 0; + } + if ( (size >>> 10) < µb.userSettings.largeMediaSize ) { return 0; } this.largeMediaCount += 1; this.largeMediaTimer.on(500); - if ( logger.enabled ) { fctxt.filter = sessionSwitches.toLogData(); } - return 1; } @@ -1116,22 +1140,31 @@ const PageStore = class { response.blockedResources = this.netFilteringCache.lookupAllBlocked(fctxt.getDocHostname()); } -}; - -PageStore.prototype.cacheableResults = new Set([ - µb.FilteringContext.SUB_FRAME, -]); -PageStore.prototype.collapsibleResources = new Set([ - µb.FilteringContext.IMAGE, - µb.FilteringContext.MEDIA, - µb.FilteringContext.OBJECT, - µb.FilteringContext.SUB_FRAME, -]); - -// To mitigate memory churning -PageStore.junkyard = []; -PageStore.junkyardMax = 10; + cacheableResults = new Set([ + µb.FilteringContext.SUB_FRAME + ]); + + collapsibleResources = new Set([ + µb.FilteringContext.IMAGE, + µb.FilteringContext.MEDIA, + µb.FilteringContext.OBJECT, + µb.FilteringContext.SUB_FRAME, + ]); + + urlSkippableResources = new Set([ + µb.FilteringContext.IMAGE, + µb.FilteringContext.MAIN_FRAME, + µb.FilteringContext.MEDIA, + µb.FilteringContext.OBJECT, + µb.FilteringContext.OTHER, + µb.FilteringContext.SUB_FRAME, + ]); + + // To mitigate memory churning + static junkyard = []; + static junkyardMax = 10; +}; /******************************************************************************/ diff --git a/src/js/redirect-engine.js b/src/js/redirect-engine.js index 1edb37624c582..d768db546f537 100644 --- a/src/js/redirect-engine.js +++ b/src/js/redirect-engine.js @@ -316,7 +316,7 @@ class RedirectEngine { this.aliases = new Map(); const fetches = [ - import('/assets/resources/scriptlets.js').then(module => { + import('/js/resources/scriptlets.js').then(module => { for ( const scriptlet of module.builtinScriptlets ) { const details = {}; details.mime = mimeFromName(scriptlet.name); @@ -333,6 +333,8 @@ class RedirectEngine { } } this.modifyTime = Date.now(); + }).catch(reason => { + console.error(reason); }), ]; diff --git a/src/js/redirect-resources.js b/src/js/redirect-resources.js index b8577e3701fcf..b1a24c61f42f4 100644 --- a/src/js/redirect-resources.js +++ b/src/js/redirect-resources.js @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ // The resources referenced below are found in ./web_accessible_resources/ @@ -159,8 +157,20 @@ export default new Map([ alias: 'nooptext', data: 'text', } ], - [ 'noop-vmap1.0.xml', { - alias: 'noopvmap-1.0', + [ 'noop-vast2.xml', { + alias: 'noopvast-2.0', + data: 'text', + } ], + [ 'noop-vast3.xml', { + alias: 'noopvast-3.0', + data: 'text', + } ], + [ 'noop-vast4.xml', { + alias: 'noopvast-4.0', + data: 'text', + } ], + [ 'noop-vmap1.xml', { + alias: [ 'noop-vmap1.0.xml', 'noopvmap-1.0' ], data: 'text', } ], [ 'outbrain-widget.js', { diff --git a/src/js/resources/attribute.js b/src/js/resources/attribute.js new file mode 100644 index 0000000000000..ed735eecdd70b --- /dev/null +++ b/src/js/resources/attribute.js @@ -0,0 +1,305 @@ +/******************************************************************************* + + 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 { runAt } from './run-at.js'; +import { safeSelf } from './safe-self.js'; + +/******************************************************************************/ + +export function setAttrFn( + trusted = false, + logPrefix, + selector = '', + attr = '', + value = '' +) { + if ( selector === '' ) { return; } + if ( attr === '' ) { return; } + + const safe = safeSelf(); + const copyFrom = trusted === false && /^\[.+\]$/.test(value) + ? value.slice(1, -1) + : ''; + + const extractValue = elem => copyFrom !== '' + ? elem.getAttribute(copyFrom) || '' + : value; + + const applySetAttr = ( ) => { + let elems; + try { + elems = document.querySelectorAll(selector); + } catch(_) { + return false; + } + for ( const elem of elems ) { + const before = elem.getAttribute(attr); + const after = extractValue(elem); + if ( after === before ) { continue; } + if ( after !== '' && /^on/i.test(attr) ) { + if ( attr.toLowerCase() in elem ) { continue; } + } + elem.setAttribute(attr, after); + safe.uboLog(logPrefix, `${attr}="${after}"`); + } + return true; + }; + + let observer, timer; + const onDomChanged = mutations => { + if ( timer !== undefined ) { return; } + let shouldWork = false; + for ( const mutation of mutations ) { + if ( mutation.addedNodes.length === 0 ) { continue; } + for ( const node of mutation.addedNodes ) { + if ( node.nodeType !== 1 ) { continue; } + shouldWork = true; + break; + } + if ( shouldWork ) { break; } + } + if ( shouldWork === false ) { return; } + timer = self.requestAnimationFrame(( ) => { + timer = undefined; + applySetAttr(); + }); + }; + + const start = ( ) => { + if ( applySetAttr() === false ) { return; } + observer = new MutationObserver(onDomChanged); + observer.observe(document.body, { + subtree: true, + childList: true, + }); + }; + runAt(( ) => { start(); }, 'idle'); +} +registerScriptlet(setAttrFn, { + name: 'set-attr.fn', + dependencies: [ + runAt, + safeSelf, + ], +}); + +/** + * @scriptlet set-attr + * + * @description + * Sets the specified attribute on the specified elements. This scriptlet runs + * once when the page loads then afterward on DOM mutations. + * + * Reference: https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-attr.js + * + * @param selector + * A CSS selector for the elements to target. + * + * @param attr + * The name of the attribute to modify. + * + * @param value + * The new value of the attribute. Supported values: + * - `''`: empty string (default) + * - `true` + * - `false` + * - positive decimal integer 0 <= value < 32768 + * - `[other]`: copy the value from attribute `other` on the same element + * + * */ + +export function setAttr( + selector = '', + attr = '', + value = '' +) { + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('set-attr', selector, attr, value); + const validValues = [ '', 'false', 'true' ]; + + if ( validValues.includes(value.toLowerCase()) === false ) { + if ( /^\d+$/.test(value) ) { + const n = parseInt(value, 10); + if ( n >= 32768 ) { return; } + value = `${n}`; + } else if ( /^\[.+\]$/.test(value) === false ) { + return; + } + } + + setAttrFn(false, logPrefix, selector, attr, value); +} +registerScriptlet(setAttr, { + name: 'set-attr.js', + dependencies: [ + safeSelf, + setAttrFn, + ], + world: 'ISOLATED', +}); + +/** + * @trustedScriptlet trusted-set-attr + * + * @description + * Sets the specified attribute on the specified elements. This scriptlet runs + * once when the page loads then afterward on DOM mutations. + * + * Reference: https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-trusted-scriptlets.md#-%EF%B8%8F-trusted-set-attr + * + * @param selector + * A CSS selector for the elements to target. + * + * @param attr + * The name of the attribute to modify. + * + * @param value + * The new value of the attribute. Since the scriptlet requires a trusted + * source, the value can be anything. + * + * */ + +export function trustedSetAttr( + selector = '', + attr = '', + value = '' +) { + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('trusted-set-attr', selector, attr, value); + setAttrFn(true, logPrefix, selector, attr, value); +} +registerScriptlet(trustedSetAttr, { + name: 'trusted-set-attr.js', + requiresTrust: true, + dependencies: [ + safeSelf, + setAttrFn, + ], + world: 'ISOLATED', +}); + +/** + * @scriptlet remove-attr + * + * @description + * Remove one or more attributes from a set of elements. + * + * @param attribute + * The name of the attribute(s) to remove. This can be a list of space- + * separated attribute names. + * + * @param [selector] + * Optional. A CSS selector for the elements to target. Default to + * `[attribute]`, or `[attribute1],[attribute2],...` if more than one + * attribute name is specified. + * + * @param [behavior] + * Optional. Space-separated tokens which modify the default behavior. + * - `asap`: Try to remove the attribute as soon as possible. Default behavior + * is to remove the attribute(s) asynchronously. + * - `stay`: Keep trying to remove the specified attribute(s) on DOM mutations. + * */ + +export function removeAttr( + rawToken = '', + rawSelector = '', + behavior = '' +) { + if ( typeof rawToken !== 'string' ) { return; } + if ( rawToken === '' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('remove-attr', rawToken, rawSelector, behavior); + const tokens = safe.String_split.call(rawToken, /\s*\|\s*/); + const selector = tokens + .map(a => `${rawSelector}[${CSS.escape(a)}]`) + .join(','); + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `Target selector:\n\t${selector}`); + } + const asap = /\basap\b/.test(behavior); + let timerId; + const rmattrAsync = ( ) => { + if ( timerId !== undefined ) { return; } + timerId = safe.onIdle(( ) => { + timerId = undefined; + rmattr(); + }, { timeout: 17 }); + }; + const rmattr = ( ) => { + if ( timerId !== undefined ) { + safe.offIdle(timerId); + timerId = undefined; + } + try { + const nodes = document.querySelectorAll(selector); + for ( const node of nodes ) { + for ( const attr of tokens ) { + if ( node.hasAttribute(attr) === false ) { continue; } + node.removeAttribute(attr); + safe.uboLog(logPrefix, `Removed attribute '${attr}'`); + } + } + } catch(ex) { + } + }; + const mutationHandler = mutations => { + if ( timerId !== undefined ) { return; } + let skip = true; + for ( let i = 0; i < mutations.length && skip; i++ ) { + const { type, addedNodes, removedNodes } = mutations[i]; + if ( type === 'attributes' ) { skip = false; } + for ( let j = 0; j < addedNodes.length && skip; j++ ) { + if ( addedNodes[j].nodeType === 1 ) { skip = false; break; } + } + for ( let j = 0; j < removedNodes.length && skip; j++ ) { + if ( removedNodes[j].nodeType === 1 ) { skip = false; break; } + } + } + if ( skip ) { return; } + asap ? rmattr() : rmattrAsync(); + }; + const start = ( ) => { + rmattr(); + if ( /\bstay\b/.test(behavior) === false ) { return; } + const observer = new MutationObserver(mutationHandler); + observer.observe(document, { + attributes: true, + attributeFilter: tokens, + childList: true, + subtree: true, + }); + }; + runAt(( ) => { start(); }, safe.String_split.call(behavior, /\s+/)); +} +registerScriptlet(removeAttr, { + name: 'remove-attr.js', + aliases: [ + 'ra.js', + ], + dependencies: [ + runAt, + safeSelf, + ], +}); + +/******************************************************************************/ diff --git a/src/js/resources/base.js b/src/js/resources/base.js new file mode 100644 index 0000000000000..2c54418a777d8 --- /dev/null +++ b/src/js/resources/base.js @@ -0,0 +1,38 @@ +/******************************************************************************* + + 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 + +*/ + +export const registeredScriptlets = []; + +export const registerScriptlet = (fn, details) => { + if ( typeof details !== 'object' ) { + throw new ReferenceError('Missing scriptlet details'); + } + details.fn = fn; + fn.details = details; + if ( Array.isArray(details.dependencies) ) { + details.dependencies.forEach((fn, i, array) => { + if ( typeof fn !== 'function' ) { return; } + array[i] = fn.details.name; + }); + } + registeredScriptlets.push(details); +}; diff --git a/src/js/resources/cookie.js b/src/js/resources/cookie.js new file mode 100644 index 0000000000000..df02ca2e93403 --- /dev/null +++ b/src/js/resources/cookie.js @@ -0,0 +1,418 @@ +/******************************************************************************* + + 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'; + +/******************************************************************************/ + +export function getSafeCookieValuesFn() { + return [ + 'accept', 'reject', + 'accepted', 'rejected', 'notaccepted', + 'allow', 'disallow', 'deny', + 'allowed', 'denied', + 'approved', 'disapproved', + 'checked', 'unchecked', + 'dismiss', 'dismissed', + 'enable', 'disable', + 'enabled', 'disabled', + 'essential', 'nonessential', + 'forbidden', 'forever', + 'hide', 'hidden', + 'necessary', 'required', + 'ok', + 'on', 'off', + 'true', 't', 'false', 'f', + 'yes', 'y', 'no', 'n', + 'all', 'none', 'functional', + ]; +} +registerScriptlet(getSafeCookieValuesFn, { + name: 'get-safe-cookie-values.fn', +}); + +/******************************************************************************/ + +export function getAllCookiesFn() { + const safe = safeSelf(); + return safe.String_split.call(document.cookie, /\s*;\s*/).map(s => { + const pos = s.indexOf('='); + if ( pos === 0 ) { return; } + if ( pos === -1 ) { return `${s.trim()}=`; } + const key = s.slice(0, pos).trim(); + const value = s.slice(pos+1).trim(); + return { key, value }; + }).filter(s => s !== undefined); +} +registerScriptlet(getAllCookiesFn, { + name: 'get-all-cookies.fn', + dependencies: [ + safeSelf, + ], +}); + +/******************************************************************************/ + +export function getCookieFn( + name = '' +) { + const safe = safeSelf(); + for ( const s of safe.String_split.call(document.cookie, /\s*;\s*/) ) { + const pos = s.indexOf('='); + if ( pos === -1 ) { continue; } + if ( s.slice(0, pos) !== name ) { continue; } + return s.slice(pos+1).trim(); + } +} +registerScriptlet(getCookieFn, { + name: 'get-cookie.fn', + dependencies: [ + safeSelf, + ], +}); + +/******************************************************************************/ + +export function setCookieFn( + trusted = false, + name = '', + value = '', + expires = '', + path = '', + options = {}, +) { + // https://datatracker.ietf.org/doc/html/rfc2616#section-2.2 + // https://github.com/uBlockOrigin/uBlock-issues/issues/2777 + if ( trusted === false && /[^!#$%&'*+\-.0-9A-Z[\]^_`a-z|~]/.test(name) ) { + name = encodeURIComponent(name); + } + // https://datatracker.ietf.org/doc/html/rfc6265#section-4.1.1 + // The characters [",] are given a pass from the RFC requirements because + // apparently browsers do not follow the RFC to the letter. + if ( /[^ -:<-[\]-~]/.test(value) ) { + value = encodeURIComponent(value); + } + + const cookieBefore = getCookieFn(name); + if ( cookieBefore !== undefined && options.dontOverwrite ) { return; } + if ( cookieBefore === value && options.reload ) { return; } + + const cookieParts = [ name, '=', value ]; + if ( expires !== '' ) { + cookieParts.push('; expires=', expires); + } + + if ( path === '' ) { path = '/'; } + else if ( path === 'none' ) { path = ''; } + if ( path !== '' && path !== '/' ) { return; } + if ( path === '/' ) { + cookieParts.push('; path=/'); + } + + if ( trusted ) { + if ( options.domain ) { + cookieParts.push(`; domain=${options.domain}`); + } + cookieParts.push('; Secure'); + } else if ( /^__(Host|Secure)-/.test(name) ) { + cookieParts.push('; Secure'); + } + + try { + document.cookie = cookieParts.join(''); + } catch(_) { + } + + const done = getCookieFn(name) === value; + if ( done && options.reload ) { + window.location.reload(); + } + + return done; +} +registerScriptlet(setCookieFn, { + name: 'set-cookie.fn', + dependencies: [ + getCookieFn, + ], +}); + +/** + * @scriptlet set-cookie + * + * @description + * Set a cookie to a safe value. + * + * @param name + * The name of the cookie to set. + * + * @param value + * The value of the cookie to set. Must be a safe value. Unsafe values will be + * ignored and no cookie will be set. See getSafeCookieValuesFn() helper above. + * + * @param [path] + * Optional. The path of the cookie to set. Default to `/`. + * + * Reference: + * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-cookie.js + * */ + +export function setCookie( + name = '', + value = '', + path = '' +) { + if ( name === '' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('set-cookie', name, value, path); + const normalized = value.toLowerCase(); + const match = /^("?)(.+)\1$/.exec(normalized); + const unquoted = match && match[2] || normalized; + const validValues = getSafeCookieValuesFn(); + if ( validValues.includes(unquoted) === false ) { + if ( /^-?\d+$/.test(unquoted) === false ) { return; } + const n = parseInt(value, 10) || 0; + if ( n < -32767 || n > 32767 ) { return; } + } + + const done = setCookieFn( + false, + name, + value, + '', + path, + safe.getExtraArgs(Array.from(arguments), 3) + ); + + if ( done ) { + safe.uboLog(logPrefix, 'Done'); + } +} +registerScriptlet(setCookie, { + name: 'set-cookie.js', + world: 'ISOLATED', + dependencies: [ + getSafeCookieValuesFn, + safeSelf, + setCookieFn, + ], +}); + +// For compatibility with AdGuard +export function setCookieReload(name, value, path, ...args) { + setCookie(name, value, path, 'reload', '1', ...args); +} +registerScriptlet(setCookieReload, { + name: 'set-cookie-reload.js', + world: 'ISOLATED', + dependencies: [ + setCookie, + ], +}); + +/** + * @trustedScriptlet trusted-set-cookie + * + * @description + * Set a cookie to any value. This scriptlet can be used only from a trusted + * source. + * + * @param name + * The name of the cookie to set. + * + * @param value + * The value of the cookie to set. Must be a safe value. Unsafe values will be + * ignored and no cookie will be set. See getSafeCookieValuesFn() helper above. + * + * @param [offsetExpiresSec] + * Optional. The path of the cookie to set. Default to `/`. + * + * @param [path] + * Optional. The path of the cookie to set. Default to `/`. + * + * Reference: + * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-cookie.js + * */ + +export function trustedSetCookie( + name = '', + value = '', + offsetExpiresSec = '', + path = '' +) { + if ( name === '' ) { return; } + + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('set-cookie', name, value, path); + const time = new Date(); + + if ( value.includes('$now$') ) { + value = value.replaceAll('$now$', time.getTime()); + } + if ( value.includes('$currentDate$') ) { + value = value.replaceAll('$currentDate$', time.toUTCString()); + } + if ( value.includes('$currentISODate$') ) { + value = value.replaceAll('$currentISODate$', time.toISOString()); + } + + let expires = ''; + if ( offsetExpiresSec !== '' ) { + if ( offsetExpiresSec === '1day' ) { + time.setDate(time.getDate() + 1); + } else if ( offsetExpiresSec === '1year' ) { + time.setFullYear(time.getFullYear() + 1); + } else { + if ( /^\d+$/.test(offsetExpiresSec) === false ) { return; } + time.setSeconds(time.getSeconds() + parseInt(offsetExpiresSec, 10)); + } + expires = time.toUTCString(); + } + + const done = setCookieFn( + true, + name, + value, + expires, + path, + safeSelf().getExtraArgs(Array.from(arguments), 4) + ); + + if ( done ) { + safe.uboLog(logPrefix, 'Done'); + } +} +registerScriptlet(trustedSetCookie, { + name: 'trusted-set-cookie.js', + requiresTrust: true, + world: 'ISOLATED', + dependencies: [ + safeSelf, + setCookieFn, + ], +}); + +// For compatibility with AdGuard +export function trustedSetCookieReload(name, value, offsetExpiresSec, path, ...args) { + trustedSetCookie(name, value, offsetExpiresSec, path, 'reload', '1', ...args); +} +registerScriptlet(trustedSetCookieReload, { + name: 'trusted-set-cookie-reload.js', + requiresTrust: true, + world: 'ISOLATED', + dependencies: [ + trustedSetCookie, + ], +}); + +/** + * @scriptlet remove-cookie + * + * @description + * Removes current site cookies specified by name. The removal operation occurs + * immediately when the scriptlet is injected, then when the page is unloaded. + * + * @param needle + * A string or a regex matching the name of the cookie(s) to remove. + * + * @param ['when', token] + * Vararg, optional. The parameter following 'when' tells when extra removal + * operations should take place. + * - `scroll`: when the page is scrolled + * - `keydown`: when a keyboard touch is pressed + * + * */ + +export function removeCookie( + needle = '' +) { + if ( typeof needle !== 'string' ) { return; } + const safe = safeSelf(); + const reName = safe.patternToRegex(needle); + const extraArgs = safe.getExtraArgs(Array.from(arguments), 1); + const throttle = (fn, ms = 500) => { + if ( throttle.timer !== undefined ) { return; } + throttle.timer = setTimeout(( ) => { + throttle.timer = undefined; + fn(); + }, ms); + }; + const remove = ( ) => { + safe.String_split.call(document.cookie, ';').forEach(cookieStr => { + const pos = cookieStr.indexOf('='); + if ( pos === -1 ) { return; } + 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; + let part2c, part2d; + const domain = document.domain; + if ( domain ) { + if ( domain !== document.location.hostname ) { + part2c = '; domain=.' + domain; + } + if ( domain.startsWith('www.') ) { + part2d = '; domain=' + domain.replace('www', ''); + } + } + const part3 = '; path=/'; + const part4 = '; Max-Age=-1000; expires=Thu, 01 Jan 1970 00:00:00 GMT'; + document.cookie = part1 + part4; + document.cookie = part1 + part2a + part4; + document.cookie = part1 + part2b + part4; + document.cookie = part1 + part3 + part4; + document.cookie = part1 + part2a + part3 + part4; + document.cookie = part1 + part2b + part3 + part4; + if ( part2c !== undefined ) { + document.cookie = part1 + part2c + part3 + part4; + } + if ( part2d !== undefined ) { + document.cookie = part1 + part2d + part3 + part4; + } + }); + }; + remove(); + window.addEventListener('beforeunload', remove); + if ( typeof extraArgs.when !== 'string' ) { return; } + const supportedEventTypes = [ 'scroll', 'keydown' ]; + const eventTypes = safe.String_split.call(extraArgs.when, /\s/); + for ( const type of eventTypes ) { + if ( supportedEventTypes.includes(type) === false ) { continue; } + document.addEventListener(type, ( ) => { + throttle(remove); + }, { passive: true }); + } +} +registerScriptlet(removeCookie, { + name: 'remove-cookie.js', + aliases: [ + 'cookie-remover.js', + ], + world: 'ISOLATED', + dependencies: [ + safeSelf, + ], +}); + +/******************************************************************************/ diff --git a/src/js/resources/localstorage.js b/src/js/resources/localstorage.js new file mode 100644 index 0000000000000..73e41546e135d --- /dev/null +++ b/src/js/resources/localstorage.js @@ -0,0 +1,235 @@ +/******************************************************************************* + + 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 { getSafeCookieValuesFn } from './cookie.js'; +import { registerScriptlet } from './base.js'; +import { safeSelf } from './safe-self.js'; + +/******************************************************************************/ + +export function getAllLocalStorageFn(which = 'localStorage') { + const storage = self[which]; + const out = []; + for ( let i = 0; i < storage.length; i++ ) { + const key = storage.key(i); + const value = storage.getItem(key); + return { key, value }; + } + return out; +} +registerScriptlet(getAllLocalStorageFn, { + name: 'get-all-local-storage.fn', +}); + +/******************************************************************************/ + +export function setLocalStorageItemFn( + which = 'local', + trusted = false, + key = '', + value = '', +) { + if ( key === '' ) { return; } + + // For increased compatibility with AdGuard + if ( value === 'emptyArr' ) { + value = '[]'; + } else if ( value === 'emptyObj' ) { + value = '{}'; + } + + const trustedValues = [ + '', + 'undefined', 'null', + '{}', '[]', '""', + '$remove$', + ...getSafeCookieValuesFn(), + ]; + + if ( trusted ) { + if ( value.includes('$now$') ) { + value = value.replaceAll('$now$', Date.now()); + } + if ( value.includes('$currentDate$') ) { + value = value.replaceAll('$currentDate$', `${Date()}`); + } + if ( value.includes('$currentISODate$') ) { + value = value.replaceAll('$currentISODate$', (new Date()).toISOString()); + } + } else { + const normalized = value.toLowerCase(); + const match = /^("?)(.+)\1$/.exec(normalized); + const unquoted = match && match[2] || normalized; + if ( trustedValues.includes(unquoted) === false ) { + if ( /^-?\d+$/.test(unquoted) === false ) { return; } + const n = parseInt(unquoted, 10) || 0; + if ( n < -32767 || n > 32767 ) { return; } + } + } + + try { + const storage = self[`${which}Storage`]; + if ( value === '$remove$' ) { + const safe = safeSelf(); + const pattern = safe.patternToRegex(key, undefined, true ); + const toRemove = []; + for ( let i = 0, n = storage.length; i < n; i++ ) { + const key = storage.key(i); + if ( pattern.test(key) ) { toRemove.push(key); } + } + for ( const key of toRemove ) { + storage.removeItem(key); + } + } else { + storage.setItem(key, `${value}`); + } + } catch(ex) { + } +} +registerScriptlet(setLocalStorageItemFn, { + name: 'set-local-storage-item.fn', + dependencies: [ + getSafeCookieValuesFn, + safeSelf, + ], +}); + +/******************************************************************************/ + +export function removeCacheStorageItem( + cacheNamePattern = '', + requestPattern = '' +) { + if ( cacheNamePattern === '' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('remove-cache-storage-item', cacheNamePattern, requestPattern); + const cacheStorage = self.caches; + if ( cacheStorage instanceof Object === false ) { return; } + const reCache = safe.patternToRegex(cacheNamePattern, undefined, true); + const reRequest = safe.patternToRegex(requestPattern, undefined, true); + cacheStorage.keys().then(cacheNames => { + for ( const cacheName of cacheNames ) { + if ( reCache.test(cacheName) === false ) { continue; } + if ( requestPattern === '' ) { + cacheStorage.delete(cacheName).then(result => { + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `Deleting ${cacheName}`); + } + if ( result !== true ) { return; } + safe.uboLog(logPrefix, `Deleted ${cacheName}: ${result}`); + }); + continue; + } + cacheStorage.open(cacheName).then(cache => { + cache.keys().then(requests => { + for ( const request of requests ) { + if ( reRequest.test(request.url) === false ) { continue; } + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `Deleting ${cacheName}/${request.url}`); + } + cache.delete(request).then(result => { + if ( result !== true ) { return; } + safe.uboLog(logPrefix, `Deleted ${cacheName}/${request.url}: ${result}`); + }); + } + }); + }); + } + }); +} +registerScriptlet(removeCacheStorageItem, { + name: 'remove-cache-storage-item.fn', + world: 'ISOLATED', + dependencies: [ + safeSelf, + ], +}); + +/******************************************************************************* + * + * set-local-storage-item.js + * set-session-storage-item.js + * + * Set a local/session storage entry to a specific, allowed value. + * + * Reference: + * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-local-storage-item.js + * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-session-storage-item.js + * + **/ + +export function setLocalStorageItem(key = '', value = '') { + setLocalStorageItemFn('local', false, key, value); +} +registerScriptlet(setLocalStorageItem, { + name: 'set-local-storage-item.js', + world: 'ISOLATED', + dependencies: [ + setLocalStorageItemFn, + ], +}); + +export function setSessionStorageItem(key = '', value = '') { + setLocalStorageItemFn('session', false, key, value); +} +registerScriptlet(setSessionStorageItem, { + name: 'set-session-storage-item.js', + world: 'ISOLATED', + dependencies: [ + setLocalStorageItemFn, + ], +}); + +/******************************************************************************* + * + * trusted-set-local-storage-item.js + * + * Set a local storage entry to an arbitrary value. + * + * Reference: + * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/trusted-set-local-storage-item.js + * + **/ + +export function trustedSetLocalStorageItem(key = '', value = '') { + setLocalStorageItemFn('local', true, key, value); +} +registerScriptlet(trustedSetLocalStorageItem, { + name: 'trusted-set-local-storage-item.js', + requiresTrust: true, + world: 'ISOLATED', + dependencies: [ + setLocalStorageItemFn, + ], +}); + +export function trustedSetSessionStorageItem(key = '', value = '') { + setLocalStorageItemFn('session', true, key, value); +} +registerScriptlet(trustedSetSessionStorageItem, { + name: 'trusted-set-session-storage-item.js', + requiresTrust: true, + world: 'ISOLATED', + dependencies: [ + setLocalStorageItemFn, + ], +}); diff --git a/src/js/resources/parse-replace.js b/src/js/resources/parse-replace.js new file mode 100644 index 0000000000000..da638735f7140 --- /dev/null +++ b/src/js/resources/parse-replace.js @@ -0,0 +1,54 @@ +/******************************************************************************* + + 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 { createArglistParser } from './shared.js'; +import { registerScriptlet } from './base.js'; + +/******************************************************************************/ + +export function parseReplaceFn(s) { + if ( s.charCodeAt(0) !== 0x2F /* / */ ) { return; } + const parser = createArglistParser('/'); + parser.nextArg(s, 1); + let pattern = s.slice(parser.argBeg, parser.argEnd); + if ( parser.transform ) { + pattern = parser.normalizeArg(pattern); + } + if ( pattern === '' ) { return; } + parser.nextArg(s, parser.separatorEnd); + let replacement = s.slice(parser.argBeg, parser.argEnd); + if ( parser.separatorEnd === parser.separatorBeg ) { return; } + if ( parser.transform ) { + replacement = parser.normalizeArg(replacement); + } + const flags = s.slice(parser.separatorEnd); + try { + return { re: new RegExp(pattern, flags), replacement }; + } catch(_) { + } +} +registerScriptlet(parseReplaceFn, { + name: 'parse-replace.fn', + dependencies: [ + createArglistParser, + ], +}); diff --git a/src/js/resources/prevent-settimeout.js b/src/js/resources/prevent-settimeout.js new file mode 100644 index 0000000000000..d8cfefad739d6 --- /dev/null +++ b/src/js/resources/prevent-settimeout.js @@ -0,0 +1,236 @@ +/******************************************************************************* + + 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'; + +/******************************************************************************/ + +class RangeParser { + constructor(s) { + this.not = s.charAt(0) === '!'; + if ( this.not ) { s = s.slice(1); } + if ( s === '' ) { return; } + const pos = s.indexOf('-'); + if ( pos !== 0 ) { + this.min = this.max = parseInt(s, 10) || 0; + } + if ( pos !== -1 ) { + this.max = parseInt(s.slice(1), 10) || Number.MAX_SAFE_INTEGER; + } + } + unbound() { + return this.min === undefined && this.max === undefined; + } + test(v) { + const n = Math.min(Math.max(Number(v) || 0, 0), Number.MAX_SAFE_INTEGER); + if ( this.min === this.max ) { + return (this.min === undefined || n === this.min) !== this.not; + } + if ( this.min === undefined ) { + return (n <= this.max) !== this.not; + } + if ( this.max === undefined ) { + return (n >= this.min) !== this.not; + } + return (n >= this.min && n <= this.max) !== this.not; + } +} +registerScriptlet(RangeParser, { + name: 'range-parser.fn', +}); + +/** + * @scriptlet prevent-setTimeout + * + * @description + * Conditionally prevent execution of the callback function passed to native + * setTimeout method. With no parameters, all calls to setTimeout will be + * shown in the logger. + * + * @param [needle] + * A pattern to match against the stringified callback. The pattern can be a + * plain string, or a regex. Prepend with `!` to reverse the match condition. + * + * @param [delay] + * A value to match against the delay. Can be a single value for exact match, + * or a range: + * - `min-max`: matches if delay >= min and delay <= max + * - `min-`: matches if delay >= min + * - `-max`: matches if delay <= max + * No delay means to match any delay value. + * Prepend with `!` to reverse the match condition. + * + * */ + +export function preventSetTimeout( + needleRaw = '', + delayRaw = '' +) { + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('prevent-setTimeout', needleRaw, delayRaw); + const needleNot = needleRaw.charAt(0) === '!'; + const reNeedle = safe.patternToRegex(needleNot ? needleRaw.slice(1) : needleRaw); + const range = new RangeParser(delayRaw); + proxyApplyFn('setTimeout', function(context) { + const { callArgs } = context; + const a = callArgs[0] instanceof Function + ? String(safe.Function_toString(callArgs[0])) + : String(callArgs[0]); + const b = callArgs[1]; + if ( needleRaw === '' && range.unbound() ) { + safe.uboLog(logPrefix, `Called:\n${a}\n${b}`); + return context.reflect(); + } + if ( reNeedle.test(a) !== needleNot && range.test(b) ) { + callArgs[0] = function(){}; + safe.uboLog(logPrefix, `Prevented:\n${a}\n${b}`); + } + return context.reflect(); + }); +} +registerScriptlet(preventSetTimeout, { + name: 'prevent-setTimeout.js', + aliases: [ + 'no-setTimeout-if.js', + 'nostif.js', + 'setTimeout-defuser.js', + ], + dependencies: [ + proxyApplyFn, + RangeParser, + safeSelf, + ], +}); + +/** + * @scriptlet prevent-setInterval + * + * @description + * Conditionally prevent execution of the callback function passed to native + * setInterval method. With no parameters, all calls to setInterval will be + * shown in the logger. + * + * @param [needle] + * A pattern to match against the stringified callback. The pattern can be a + * plain string, or a regex. Prepend with `!` to reverse the match condition. + * No pattern means to match anything. + * + * @param [delay] + * A value to match against the delay. Can be a single value for exact match, + * or a range: + * - `min-max`: matches if delay >= min and delay <= max + * - `min-`: matches if delay >= min + * - `-max`: matches if delay <= max + * No delay means to match any delay value. + * Prepend with `!` to reverse the match condition. + * + * */ + +export function preventSetInterval( + needleRaw = '', + delayRaw = '' +) { + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('prevent-setInterval', needleRaw, delayRaw); + const needleNot = needleRaw.charAt(0) === '!'; + const reNeedle = safe.patternToRegex(needleNot ? needleRaw.slice(1) : needleRaw); + const range = new RangeParser(delayRaw); + proxyApplyFn('setInterval', function(context) { + const { callArgs } = context; + const a = callArgs[0] instanceof Function + ? String(safe.Function_toString(callArgs[0])) + : String(callArgs[0]); + const b = callArgs[1]; + if ( needleRaw === '' && range.unbound() ) { + safe.uboLog(logPrefix, `Called:\n${a}\n${b}`); + return context.reflect(); + } + if ( reNeedle.test(a) !== needleNot && range.test(b) ) { + callArgs[0] = function(){}; + safe.uboLog(logPrefix, `Prevented:\n${a}\n${b}`); + } + return context.reflect(); + }); +} +registerScriptlet(preventSetInterval, { + name: 'prevent-setInterval.js', + aliases: [ + 'no-setInterval-if.js', + 'nosiif.js', + 'setInterval-defuser.js', + ], + dependencies: [ + proxyApplyFn, + RangeParser, + safeSelf, + ], +}); + +/** + * @scriptlet prevent-requestAnimationFrame + * + * @description + * Conditionally prevent execution of the callback function passed to native + * requestAnimationFrame method. With no parameters, all calls to + * requestAnimationFrame will be shown in the logger. + * + * @param [needle] + * A pattern to match against the stringified callback. The pattern can be a + * plain string, or a regex. + * Prepend with `!` to reverse the match condition. + * + * */ + +export function preventRequestAnimationFrame( + needleRaw = '' +) { + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('prevent-requestAnimationFrame', needleRaw); + const needleNot = needleRaw.charAt(0) === '!'; + const reNeedle = safe.patternToRegex(needleNot ? needleRaw.slice(1) : needleRaw); + proxyApplyFn('requestAnimationFrame', function(context) { + const { callArgs } = context; + const a = callArgs[0] instanceof Function + ? String(safe.Function_toString(callArgs[0])) + : String(callArgs[0]); + if ( needleRaw === '' ) { + safe.uboLog(logPrefix, `Called:\n${a}`); + } else if ( reNeedle.test(a) !== needleNot ) { + callArgs[0] = function(){}; + safe.uboLog(logPrefix, `Prevented:\n${a}`); + } + return context.reflect(); + }); +} +registerScriptlet(preventRequestAnimationFrame, { + name: 'prevent-requestAnimationFrame.js', + aliases: [ + 'no-requestAnimationFrame-if.js', + 'norafif.js', + ], + dependencies: [ + proxyApplyFn, + safeSelf, + ], +}); diff --git a/src/js/resources/proxy-apply.js b/src/js/resources/proxy-apply.js new file mode 100644 index 0000000000000..60326f54617e2 --- /dev/null +++ b/src/js/resources/proxy-apply.js @@ -0,0 +1,109 @@ +/******************************************************************************* + + 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'; + +/******************************************************************************/ + +export function proxyApplyFn( + target = '', + handler = '' +) { + let context = globalThis; + let prop = target; + 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); + } + const fn = context[prop]; + if ( typeof fn !== 'function' ) { return; } + if ( proxyApplyFn.CtorContext === undefined ) { + proxyApplyFn.ctorContexts = []; + proxyApplyFn.CtorContext = class { + constructor(...args) { + this.init(...args); + } + init(callFn, callArgs) { + this.callFn = callFn; + this.callArgs = callArgs; + return this; + } + reflect() { + const r = Reflect.construct(this.callFn, this.callArgs); + this.callFn = this.callArgs = this.private = undefined; + proxyApplyFn.ctorContexts.push(this); + return r; + } + static factory(...args) { + return proxyApplyFn.ctorContexts.length !== 0 + ? proxyApplyFn.ctorContexts.pop().init(...args) + : new proxyApplyFn.CtorContext(...args); + } + }; + proxyApplyFn.applyContexts = []; + proxyApplyFn.ApplyContext = class { + constructor(...args) { + this.init(...args); + } + init(callFn, thisArg, callArgs) { + this.callFn = callFn; + this.thisArg = thisArg; + this.callArgs = callArgs; + return this; + } + reflect() { + const r = Reflect.apply(this.callFn, this.thisArg, this.callArgs); + this.callFn = this.thisArg = this.callArgs = this.private = undefined; + proxyApplyFn.applyContexts.push(this); + return r; + } + static factory(...args) { + return proxyApplyFn.applyContexts.length !== 0 + ? proxyApplyFn.applyContexts.pop().init(...args) + : new proxyApplyFn.ApplyContext(...args); + } + }; + } + const fnStr = fn.toString(); + const toString = (function toString() { return fnStr; }).bind(null); + const proxyDetails = { + apply(target, thisArg, args) { + return handler(proxyApplyFn.ApplyContext.factory(target, thisArg, args)); + }, + get(target, prop) { + if ( prop === 'toString' ) { return toString; } + return Reflect.get(target, prop); + }, + }; + if ( fn.prototype?.constructor === fn ) { + proxyDetails.construct = function(target, args) { + return handler(proxyApplyFn.CtorContext.factory(target, args)); + }; + } + context[prop] = new Proxy(fn, proxyDetails); +} +registerScriptlet(proxyApplyFn, { + name: 'proxy-apply.fn', +}); diff --git a/src/js/resources/replace-argument.js b/src/js/resources/replace-argument.js new file mode 100644 index 0000000000000..c5927d2b9dc35 --- /dev/null +++ b/src/js/resources/replace-argument.js @@ -0,0 +1,120 @@ +/******************************************************************************* + + 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 { parseReplaceFn } from './parse-replace.js'; +import { proxyApplyFn } from './proxy-apply.js'; +import { registerScriptlet } from './base.js'; +import { safeSelf } from './safe-self.js'; +import { validateConstantFn } from './set-constant.js'; + +/** + * @scriptlet trusted-replace-argument.js + * + * @description + * Replace an argument passed to a method. Requires a trusted source. + * + * @param propChain + * The property chain to the function which argument must be replaced when + * called. + * + * @param argposRaw + * The zero-based position of the argument in the argument list. Use a negative + * number for a position relative to the last argument. Use literal `this` to + * replace the value used in `prototype`-based methods. + * + * @param argraw + * The replacement value, validated using the same heuristic as with the + * `set-constant.js` scriptlet. + * If the replacement value matches `json:...`, the value will be the + * json-parsed string after `json:`. + * If the replacement value matches `repl:/.../.../`, the target argument will + * be replaced according the regex-replacement directive following `repl:` + * + * @param [, condition, pattern] + * Optional. The replacement will occur only when pattern matches the target + * argument. + * + * */ + +export function trustedReplaceArgument( + propChain = '', + argposRaw = '', + argraw = '' +) { + if ( propChain === '' ) { return; } + const safe = safeSelf(); + 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; + const reCondition = extraArgs.condition + ? safe.patternToRegex(extraArgs.condition) + : /^/; + const getArg = context => { + if ( argposRaw === 'this' ) { return context.thisArg; } + const { callArgs } = context; + const argpos = argoffset >= 0 ? argoffset : callArgs.length - argoffset; + if ( argpos < 0 || argpos >= callArgs.length ) { return; } + context.private = { argpos }; + return callArgs[argpos]; + }; + const setArg = (context, value) => { + if ( argposRaw === 'this' ) { + if ( value !== context.thisArg ) { + context.thisArg = value; + } + } else if ( context.private ) { + context.callArgs[context.private.argpos] = value; + } + }; + proxyApplyFn(propChain, function(context) { + if ( argposRaw === '' ) { + safe.uboLog(logPrefix, `Arguments:\n${context.callArgs.join('\n')}`); + return context.reflect(); + } + const argBefore = getArg(context); + if ( safe.RegExp_test.call(reCondition, argBefore) === false ) { + return context.reflect(); + } + const argAfter = replacer && typeof argBefore === 'string' + ? argBefore.replace(replacer.re, replacer.replacement) + : value; + if ( argAfter !== argBefore ) { + setArg(context, argAfter); + safe.uboLog(logPrefix, `Replaced argument:\nBefore: ${JSON.stringify(argBefore)}\nAfter: ${argAfter}`); + } + return context.reflect(); + }); +} +registerScriptlet(trustedReplaceArgument, { + name: 'trusted-replace-argument.js', + requiresTrust: true, + dependencies: [ + parseReplaceFn, + proxyApplyFn, + safeSelf, + validateConstantFn, + ], +}); diff --git a/src/js/resources/run-at.js b/src/js/resources/run-at.js new file mode 100644 index 0000000000000..545324dcf1160 --- /dev/null +++ b/src/js/resources/run-at.js @@ -0,0 +1,96 @@ +/******************************************************************************* + + 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'; + +/* eslint no-prototype-builtins: 0 */ + +/** + * @helperScriptlet run-at.fn + * + * @description + * Execute a function at a specific page-load milestone. + * + * @param fn + * The function to call. + * + * @param when + * An identifier which tells when the function should be executed. + * See . + * + * @example + * `runAt(( ) => { start(); }, 'interactive')` + * + * */ + +export function runAt(fn, when) { + const intFromReadyState = state => { + const targets = { + 'loading': 1, 'asap': 1, + 'interactive': 2, 'end': 2, '2': 2, + 'complete': 3, 'idle': 3, '3': 3, + }; + const tokens = Array.isArray(state) ? state : [ state ]; + for ( const token of tokens ) { + const prop = `${token}`; + if ( targets.hasOwnProperty(prop) === false ) { continue; } + return targets[prop]; + } + return 0; + }; + const runAt = intFromReadyState(when); + if ( intFromReadyState(document.readyState) >= runAt ) { + fn(); return; + } + const onStateChange = ( ) => { + if ( intFromReadyState(document.readyState) < runAt ) { return; } + fn(); + safe.removeEventListener.apply(document, args); + }; + const safe = safeSelf(); + const args = [ 'readystatechange', onStateChange, { capture: true } ]; + safe.addEventListener.apply(document, args); +} +registerScriptlet(runAt, { + name: 'run-at.fn', + dependencies: [ + safeSelf, + ], +}); + +/******************************************************************************/ + +export function runAtHtmlElementFn(fn) { + if ( document.documentElement ) { + fn(); + return; + } + const observer = new MutationObserver(( ) => { + observer.disconnect(); + fn(); + }); + observer.observe(document, { childList: true }); +} +registerScriptlet(runAtHtmlElementFn, { + name: 'run-at-html-element.fn', +}); diff --git a/src/js/resources/safe-self.js b/src/js/resources/safe-self.js new file mode 100644 index 0000000000000..afb98722113fa --- /dev/null +++ b/src/js/resources/safe-self.js @@ -0,0 +1,219 @@ +/******************************************************************************* + + 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'; + +/******************************************************************************/ + +// Externally added to the private namespace in which scriptlets execute. +/* global scriptletGlobals */ + +export function safeSelf() { + if ( scriptletGlobals.safeSelf ) { + return scriptletGlobals.safeSelf; + } + const self = globalThis; + const safe = { + 'Array_from': Array.from, + 'Error': self.Error, + 'Function_toStringFn': self.Function.prototype.toString, + 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Math_floor': Math.floor, + 'Math_max': Math.max, + 'Math_min': Math.min, + 'Math_random': Math.random, + 'Object': Object, + 'Object_defineProperty': Object.defineProperty.bind(Object), + 'Object_defineProperties': Object.defineProperties.bind(Object), + 'Object_fromEntries': Object.fromEntries.bind(Object), + 'Object_getOwnPropertyDescriptor': Object.getOwnPropertyDescriptor.bind(Object), + 'RegExp': self.RegExp, + 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_exec': self.RegExp.prototype.exec, + 'Request_clone': self.Request.prototype.clone, + 'String_fromCharCode': String.fromCharCode, + 'String_split': String.prototype.split, + 'XMLHttpRequest': self.XMLHttpRequest, + 'addEventListener': self.EventTarget.prototype.addEventListener, + 'removeEventListener': self.EventTarget.prototype.removeEventListener, + 'fetch': self.fetch, + 'JSON': self.JSON, + 'JSON_parseFn': self.JSON.parse, + 'JSON_stringifyFn': self.JSON.stringify, + 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), + 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'log': console.log.bind(console), + // Properties + logLevel: 0, + // Methods + makeLogPrefix(...args) { + return this.sendToLogger && `[${args.join(' \u205D ')}]` || ''; + }, + uboLog(...args) { + if ( this.sendToLogger === undefined ) { return; } + if ( args === undefined || args[0] === '' ) { return; } + return this.sendToLogger('info', ...args); + + }, + uboErr(...args) { + if ( this.sendToLogger === undefined ) { return; } + if ( args === undefined || args[0] === '' ) { return; } + return this.sendToLogger('error', ...args); + }, + escapeRegexChars(s) { + return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + }, + initPattern(pattern, options = {}) { + if ( pattern === '' ) { + return { matchAll: true, expect: true }; + } + const expect = (options.canNegate !== true || pattern.startsWith('!') === false); + if ( expect === false ) { + pattern = pattern.slice(1); + } + const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern); + if ( match !== null ) { + return { + re: new this.RegExp( + match[1], + match[2] || options.flags + ), + expect, + }; + } + if ( options.flags !== undefined ) { + return { + re: new this.RegExp(this.escapeRegexChars(pattern), + options.flags + ), + expect, + }; + } + return { pattern, expect }; + }, + testPattern(details, haystack) { + if ( details.matchAll ) { return true; } + if ( details.re ) { + return this.RegExp_test.call(details.re, haystack) === details.expect; + } + return haystack.includes(details.pattern) === details.expect; + }, + patternToRegex(pattern, flags = undefined, verbatim = false) { + if ( pattern === '' ) { return /^/; } + const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern); + if ( match === null ) { + const reStr = this.escapeRegexChars(pattern); + return new RegExp(verbatim ? `^${reStr}$` : reStr, flags); + } + try { + return new RegExp(match[1], match[2] || undefined); + } + catch(ex) { + } + return /^/; + }, + getExtraArgs(args, offset = 0) { + const entries = args.slice(offset).reduce((out, v, i, a) => { + if ( (i & 1) === 0 ) { + const rawValue = a[i+1]; + const value = /^\d+$/.test(rawValue) + ? parseInt(rawValue, 10) + : rawValue; + out.push([ a[i], value ]); + } + return out; + }, []); + return this.Object_fromEntries(entries); + }, + onIdle(fn, options) { + if ( self.requestIdleCallback ) { + return self.requestIdleCallback(fn, options); + } + return self.requestAnimationFrame(fn); + }, + offIdle(id) { + if ( self.requestIdleCallback ) { + return self.cancelIdleCallback(id); + } + return self.cancelAnimationFrame(id); + } + }; + scriptletGlobals.safeSelf = safe; + if ( scriptletGlobals.bcSecret === undefined ) { return safe; } + // This is executed only when the logger is opened + safe.logLevel = scriptletGlobals.logLevel || 1; + let lastLogType = ''; + let lastLogText = ''; + let lastLogTime = 0; + safe.toLogText = (type, ...args) => { + if ( args.length === 0 ) { return; } + const text = `[${document.location.hostname || document.location.href}]${args.join(' ')}`; + if ( text === lastLogText && type === lastLogType ) { + if ( (Date.now() - lastLogTime) < 5000 ) { return; } + } + lastLogType = type; + lastLogText = text; + lastLogTime = Date.now(); + return text; + }; + try { + const bc = new self.BroadcastChannel(scriptletGlobals.bcSecret); + let bcBuffer = []; + safe.sendToLogger = (type, ...args) => { + const text = safe.toLogText(type, ...args); + if ( text === undefined ) { return; } + if ( bcBuffer === undefined ) { + return bc.postMessage({ what: 'messageToLogger', type, text }); + } + bcBuffer.push({ type, text }); + }; + bc.onmessage = ev => { + const msg = ev.data; + switch ( msg ) { + case 'iamready!': + if ( bcBuffer === undefined ) { break; } + bcBuffer.forEach(({ type, text }) => + bc.postMessage({ what: 'messageToLogger', type, text }) + ); + bcBuffer = undefined; + break; + case 'setScriptletLogLevelToOne': + safe.logLevel = 1; + break; + case 'setScriptletLogLevelToTwo': + safe.logLevel = 2; + break; + } + }; + bc.postMessage('areyouready?'); + } catch(_) { + safe.sendToLogger = (type, ...args) => { + const text = safe.toLogText(type, ...args); + if ( text === undefined ) { return; } + safe.log(`uBO ${text}`); + }; + } + return safe; +} +registerScriptlet(safeSelf, { + name: 'safe-self.fn', +}); diff --git a/assets/resources/scriptlets.js b/src/js/resources/scriptlets.js similarity index 61% rename from assets/resources/scriptlets.js rename to src/js/resources/scriptlets.js index 54adfb623376a..aeb0f096180c4 100644 --- a/assets/resources/scriptlets.js +++ b/src/js/resources/scriptlets.js @@ -18,16 +18,28 @@ Home: https://github.com/gorhill/uBlock - The scriptlets below are meant to be injected only into a - web page context. */ -/* eslint no-prototype-builtins: 0 */ +import './attribute.js'; +import './replace-argument.js'; +import './spoof-css.js'; +import './prevent-settimeout.js'; + +import { runAt, runAtHtmlElementFn } from './run-at.js'; + +import { getAllCookiesFn } from './cookie.js'; +import { getAllLocalStorageFn } from './localstorage.js'; +import { proxyApplyFn } from './proxy-apply.js'; +import { registeredScriptlets } from './base.js'; +import { safeSelf } from './safe-self.js'; +import { validateConstantFn } from './set-constant.js'; // Externally added to the private namespace in which scriptlets execute. /* global scriptletGlobals */ -export const builtinScriptlets = []; +/* eslint no-prototype-builtins: 0 */ + +export const builtinScriptlets = registeredScriptlets; /******************************************************************************* @@ -38,180 +50,28 @@ export const builtinScriptlets = []; *******************************************************************************/ builtinScriptlets.push({ - name: 'safe-self.fn', - fn: safeSelf, + name: 'get-random-token.fn', + fn: getRandomToken, + dependencies: [ + 'safe-self.fn', + ], }); -function safeSelf() { - if ( scriptletGlobals.safeSelf ) { - return scriptletGlobals.safeSelf; - } - const self = globalThis; - const safe = { - 'Array_from': Array.from, - 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), - 'Math_floor': Math.floor, - 'Math_max': Math.max, - 'Math_min': Math.min, - 'Math_random': Math.random, - 'Object': Object, - 'Object_defineProperty': Object.defineProperty.bind(Object), - 'Object_fromEntries': Object.fromEntries.bind(Object), - 'Object_getOwnPropertyDescriptor': Object.getOwnPropertyDescriptor.bind(Object), - 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, - 'RegExp_exec': self.RegExp.prototype.exec, - 'Request_clone': self.Request.prototype.clone, - 'XMLHttpRequest': self.XMLHttpRequest, - 'addEventListener': self.EventTarget.prototype.addEventListener, - 'removeEventListener': self.EventTarget.prototype.removeEventListener, - 'fetch': self.fetch, - 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), - 'log': console.log.bind(console), - // Properties - logLevel: 0, - // Methods - makeLogPrefix(...args) { - return this.sendToLogger && `[${args.join(' \u205D ')}]` || ''; - }, - uboLog(...args) { - if ( this.sendToLogger === undefined ) { return; } - if ( args === undefined || args[0] === '' ) { return; } - return this.sendToLogger('info', ...args); - - }, - uboErr(...args) { - if ( this.sendToLogger === undefined ) { return; } - if ( args === undefined || args[0] === '' ) { return; } - return this.sendToLogger('error', ...args); - }, - escapeRegexChars(s) { - return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - }, - initPattern(pattern, options = {}) { - if ( pattern === '' ) { - return { matchAll: true }; - } - const expect = (options.canNegate !== true || pattern.startsWith('!') === false); - if ( expect === false ) { - pattern = pattern.slice(1); - } - const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern); - if ( match !== null ) { - return { - re: new this.RegExp( - match[1], - match[2] || options.flags - ), - expect, - }; - } - if ( options.flags !== undefined ) { - return { - re: new this.RegExp(this.escapeRegexChars(pattern), - options.flags - ), - expect, - }; - } - return { pattern, expect }; - }, - testPattern(details, haystack) { - if ( details.matchAll ) { return true; } - if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; - } - return haystack.includes(details.pattern) === details.expect; - }, - patternToRegex(pattern, flags = undefined, verbatim = false) { - if ( pattern === '' ) { return /^/; } - const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern); - if ( match === null ) { - const reStr = this.escapeRegexChars(pattern); - return new RegExp(verbatim ? `^${reStr}$` : reStr, flags); - } - try { - return new RegExp(match[1], match[2] || undefined); - } - catch(ex) { - } - return /^/; - }, - getExtraArgs(args, offset = 0) { - const entries = args.slice(offset).reduce((out, v, i, a) => { - if ( (i & 1) === 0 ) { - const rawValue = a[i+1]; - const value = /^\d+$/.test(rawValue) - ? parseInt(rawValue, 10) - : rawValue; - out.push([ a[i], value ]); - } - return out; - }, []); - return this.Object_fromEntries(entries); - }, - onIdle(fn, options) { - if ( self.requestIdleCallback ) { - return self.requestIdleCallback(fn, options); - } - return self.requestAnimationFrame(fn); - }, - }; - scriptletGlobals.safeSelf = safe; - if ( scriptletGlobals.bcSecret === undefined ) { return safe; } - // This is executed only when the logger is opened - const bc = new self.BroadcastChannel(scriptletGlobals.bcSecret); - let bcBuffer = []; - safe.logLevel = scriptletGlobals.logLevel || 1; - safe.sendToLogger = (type, ...args) => { - if ( args.length === 0 ) { return; } - const text = `[${document.location.hostname || document.location.href}]${args.join(' ')}`; - if ( bcBuffer === undefined ) { - return bc.postMessage({ what: 'messageToLogger', type, text }); - } - bcBuffer.push({ type, text }); - }; - bc.onmessage = ev => { - const msg = ev.data; - switch ( msg ) { - case 'iamready!': - if ( bcBuffer === undefined ) { break; } - bcBuffer.forEach(({ type, text }) => - bc.postMessage({ what: 'messageToLogger', type, text }) - ); - bcBuffer = undefined; - break; - case 'setScriptletLogLevelToOne': - safe.logLevel = 1; - break; - case 'setScriptletLogLevelToTwo': - safe.logLevel = 2; - break; - } - }; - bc.postMessage('areyouready?'); - return safe; +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: [ - 'safe-self.fn', + 'get-random-token.fn', ], }); function getExceptionToken() { - const safe = safeSelf(); - const token = - String.fromCharCode(Date.now() % 26 + 97) + - safe.Math_floor(safe.Math_random() * 982451653 + 982451653).toString(36); + const token = getRandomToken(); const oe = self.onerror; self.onerror = function(msg, ...args) { if ( typeof msg === 'string' && msg.includes(token) ) { return true; } @@ -235,64 +95,11 @@ function shouldDebug(details) { /******************************************************************************/ -builtinScriptlets.push({ - name: 'run-at.fn', - fn: runAt, - dependencies: [ - 'safe-self.fn', - ], -}); -function runAt(fn, when) { - const intFromReadyState = state => { - const targets = { - 'loading': 1, - 'interactive': 2, 'end': 2, '2': 2, - 'complete': 3, 'idle': 3, '3': 3, - }; - const tokens = Array.isArray(state) ? state : [ state ]; - for ( const token of tokens ) { - const prop = `${token}`; - if ( targets.hasOwnProperty(prop) === false ) { continue; } - return targets[prop]; - } - return 0; - }; - const runAt = intFromReadyState(when); - if ( intFromReadyState(document.readyState) >= runAt ) { - fn(); return; - } - const onStateChange = ( ) => { - if ( intFromReadyState(document.readyState) < runAt ) { return; } - fn(); - safe.removeEventListener.apply(document, args); - }; - const safe = safeSelf(); - const args = [ 'readystatechange', onStateChange, { capture: true } ]; - safe.addEventListener.apply(document, args); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'run-at-html-element.fn', - fn: runAtHtmlElementFn, -}); -function runAtHtmlElementFn(fn) { - if ( document.documentElement ) { - fn(); - return; - } - const observer = new MutationObserver(( ) => { - observer.disconnect(); - fn(); - }); - observer.observe(document, { childList: true }); -} - -/******************************************************************************/ - // 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', @@ -301,7 +108,7 @@ builtinScriptlets.push({ 'safe-self.fn', ], }); -function generateContentFn(directive) { +function generateContentFn(trusted, directive) { const safe = safeSelf(); const randomize = len => { const chunks = []; @@ -315,27 +122,27 @@ function generateContentFn(directive) { return chunks.join(' ').slice(0, len); }; if ( directive === 'true' ) { - return Promise.resolve(randomize(10)); + return randomize(10); } if ( directive === 'emptyObj' ) { - return Promise.resolve('{}'); + return '{}'; } if ( directive === 'emptyArr' ) { - return Promise.resolve('[]'); + return '[]'; } if ( directive === 'emptyStr' ) { - return Promise.resolve(''); + return ''; } if ( directive.startsWith('length:') ) { const match = /^length:(\d+)(?:-(\d+))?$/.exec(directive); - if ( match ) { - 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 Promise.resolve(randomize(len | 0)); - } - } - if ( directive.startsWith('war:') && scriptletGlobals.warOrigin ) { + 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); @@ -351,9 +158,12 @@ function generateContentFn(directive) { }; warXHR.open('GET', fullpath.join('')); warXHR.send(); - }); + }).catch(( ) => ''); } - return Promise.resolve(''); + if ( trusted ) { + return directive; + } + return ''; } /******************************************************************************/ @@ -382,7 +192,7 @@ function abortCurrentScriptCore( const reContext = safe.patternToRegex(context); const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); const thisScript = document.currentScript; - const chain = target.split('.'); + const chain = safe.String_split.call(target, '.'); let owner = window; let prop; for (;;) { @@ -477,229 +287,11 @@ function abortCurrentScriptCore( /******************************************************************************/ -builtinScriptlets.push({ - name: 'validate-constant.fn', - fn: validateConstantFn, - dependencies: [ - 'safe-self.fn', - ], -}); -function validateConstantFn(trusted, raw) { - const safe = safeSelf(); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); - let value; - if ( raw === 'undefined' ) { - value = undefined; - } else if ( raw === 'false' ) { - value = false; - } else if ( raw === 'true' ) { - value = true; - } else if ( raw === 'null' ) { - value = null; - } else if ( raw === "''" || raw === '' ) { - value = ''; - } else if ( raw === '[]' || raw === 'emptyArr' ) { - value = []; - } else if ( raw === '{}' || raw === 'emptyObj' ) { - value = {}; - } else if ( raw === 'noopFunc' ) { - value = function(){}; - } else if ( raw === 'trueFunc' ) { - value = function(){ return true; }; - } else if ( raw === 'falseFunc' ) { - value = function(){ return false; }; - } else if ( /^-?\d+$/.test(raw) ) { - value = parseInt(raw); - if ( isNaN(raw) ) { return; } - if ( Math.abs(raw) > 0x7FFF ) { return; } - } else if ( trusted ) { - if ( raw.startsWith('{') && raw.endsWith('}') ) { - try { value = safe.JSON_parse(raw).value; } catch(ex) { return; } - } - } else { - return; - } - if ( extraArgs.as !== undefined ) { - if ( extraArgs.as === 'function' ) { - return ( ) => value; - } else if ( extraArgs.as === 'callback' ) { - return ( ) => (( ) => value); - } else if ( extraArgs.as === 'resolved' ) { - return Promise.resolve(value); - } else if ( extraArgs.as === 'rejected' ) { - return Promise.reject(value); - } - } - return value; -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'set-constant.fn', - fn: setConstantFn, - dependencies: [ - 'run-at.fn', - 'safe-self.fn', - 'validate-constant.fn', - ], -}); -function setConstantFn( - trusted = false, - chain = '', - rawValue = '' -) { - if ( chain === '' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('set-constant', chain, rawValue); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); - function setConstant(chain, rawValue) { - const trappedProp = (( ) => { - const pos = chain.lastIndexOf('.'); - if ( pos === -1 ) { return chain; } - return chain.slice(pos+1); - })(); - const cloakFunc = fn => { - safe.Object_defineProperty(fn, 'name', { value: trappedProp }); - return new Proxy(fn, { - defineProperty(target, prop) { - if ( prop !== 'toString' ) { - return Reflect.defineProperty(...arguments); - } - return true; - }, - deleteProperty(target, prop) { - if ( prop !== 'toString' ) { - return Reflect.deleteProperty(...arguments); - } - return true; - }, - get(target, prop) { - if ( prop === 'toString' ) { - return function() { - return `function ${trappedProp}() { [native code] }`; - }.bind(null); - } - return Reflect.get(...arguments); - }, - }); - }; - if ( trappedProp === '' ) { return; } - const thisScript = document.currentScript; - let normalValue = validateConstantFn(trusted, rawValue); - if ( rawValue === 'noopFunc' || rawValue === 'trueFunc' || rawValue === 'falseFunc' ) { - normalValue = cloakFunc(normalValue); - } - let aborted = false; - const mustAbort = function(v) { - if ( trusted ) { return false; } - if ( aborted ) { return true; } - aborted = - (v !== undefined && v !== null) && - (normalValue !== undefined && normalValue !== null) && - (typeof v !== typeof normalValue); - if ( aborted ) { - safe.uboLog(logPrefix, `Aborted because value set to ${v}`); - } - return aborted; - }; - // https://github.com/uBlockOrigin/uBlock-issues/issues/156 - // Support multiple trappers for the same property. - const trapProp = function(owner, prop, configurable, handler) { - if ( handler.init(configurable ? owner[prop] : normalValue) === false ) { return; } - const odesc = safe.Object_getOwnPropertyDescriptor(owner, prop); - let prevGetter, prevSetter; - if ( odesc instanceof safe.Object ) { - owner[prop] = normalValue; - if ( odesc.get instanceof Function ) { - prevGetter = odesc.get; - } - if ( odesc.set instanceof Function ) { - prevSetter = odesc.set; - } - } - try { - safe.Object_defineProperty(owner, prop, { - configurable, - get() { - if ( prevGetter !== undefined ) { - prevGetter(); - } - return handler.getter(); - }, - set(a) { - if ( prevSetter !== undefined ) { - prevSetter(a); - } - handler.setter(a); - } - }); - safe.uboLog(logPrefix, 'Trap installed'); - } catch(ex) { - safe.uboErr(logPrefix, ex); - } - }; - const trapChain = function(owner, chain) { - const pos = chain.indexOf('.'); - if ( pos === -1 ) { - trapProp(owner, chain, false, { - v: undefined, - init: function(v) { - if ( mustAbort(v) ) { return false; } - this.v = v; - return true; - }, - getter: function() { - if ( document.currentScript === thisScript ) { - return this.v; - } - safe.uboLog(logPrefix, 'Property read'); - return normalValue; - }, - setter: function(a) { - if ( mustAbort(a) === false ) { return; } - normalValue = a; - } - }); - return; - } - const prop = chain.slice(0, pos); - const v = owner[prop]; - chain = chain.slice(pos + 1); - if ( v instanceof safe.Object || typeof v === 'object' && v !== null ) { - trapChain(v, chain); - return; - } - trapProp(owner, prop, true, { - v: undefined, - init: function(v) { - this.v = v; - return true; - }, - getter: function() { - return this.v; - }, - setter: function(a) { - this.v = a; - if ( a instanceof safe.Object ) { - trapChain(a, chain); - } - } - }); - }; - trapChain(window, chain); - } - runAt(( ) => { - setConstant(chain, rawValue); - }, extraArgs.runAt); -} - -/******************************************************************************/ - builtinScriptlets.push({ name: 'replace-node-text.fn', fn: replaceNodeTextFn, dependencies: [ + 'get-random-token.fn', 'run-at.fn', 'safe-self.fn', ], @@ -714,7 +306,12 @@ function replaceNodeTextFn( const reNodeName = safe.patternToRegex(nodeName, 'i', true); const rePattern = safe.patternToRegex(pattern, 'gms'); const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); - const reCondition = safe.patternToRegex(extraArgs.condition || '', 'ms'); + const reIncludes = extraArgs.includes || extraArgs.condition + ? safe.patternToRegex(extraArgs.includes || extraArgs.condition, 'ms') + : null; + const reExcludes = extraArgs.excludes + ? safe.patternToRegex(extraArgs.excludes, 'ms') + : null; const stop = (takeRecord = true) => { if ( takeRecord ) { handleMutations(observer.takeRecords()); @@ -724,18 +321,38 @@ function replaceNodeTextFn( safe.uboLog(logPrefix, 'Quitting'); } }; + const textContentFactory = (( ) => { + const out = { createScript: s => s }; + const { trustedTypes: tt } = self; + if ( tt instanceof Object ) { + if ( typeof tt.getPropertyType === 'function' ) { + if ( tt.getPropertyType('script', 'textContent') === 'TrustedScript' ) { + return tt.createPolicy(getRandomToken(), out); + } + } + } + return out; + })(); let sedCount = extraArgs.sedCount || 0; const handleNode = node => { const before = node.textContent; - reCondition.lastIndex = 0; - if ( safe.RegExp_test.call(reCondition, before) === false ) { return true; } + if ( reIncludes ) { + reIncludes.lastIndex = 0; + if ( safe.RegExp_test.call(reIncludes, before) === false ) { return true; } + } + if ( reExcludes ) { + reExcludes.lastIndex = 0; + if ( safe.RegExp_test.call(reExcludes, before) ) { return true; } + } rePattern.lastIndex = 0; if ( safe.RegExp_test.call(rePattern, before) === false ) { return true; } rePattern.lastIndex = 0; const after = pattern !== '' ? before.replace(rePattern, replacement) : replacement; - node.textContent = after; + node.textContent = node.nodeName === 'SCRIPT' + ? textContentFactory.createScript(after) + : after; if ( safe.logLevel > 1 ) { safe.uboLog(logPrefix, `Text before:\n${before.trim()}`); } @@ -764,6 +381,7 @@ function replaceNodeTextFn( count += 1; if ( node === null ) { break; } if ( reNodeName.test(node.nodeName) === false ) { continue; } + if ( node === document.currentScript ) { continue; } if ( handleNode(node) ) { continue; } stop(); break; } @@ -788,6 +406,7 @@ builtinScriptlets.push({ dependencies: [ 'matches-stack-trace.fn', 'object-find-owner.fn', + 'safe-self.fn', ], }); // When no "prune paths" argument is provided, the scriptlet is @@ -804,14 +423,15 @@ function objectPruneFn( extraArgs = {} ) { if ( typeof rawPrunePaths !== 'string' ) { return; } + const safe = safeSelf(); const prunePaths = rawPrunePaths !== '' - ? rawPrunePaths.split(/ +/) + ? safe.String_split.call(rawPrunePaths, / +/) : []; const needlePaths = prunePaths.length !== 0 && rawNeedlePaths !== '' - ? rawNeedlePaths.split(/ +/) + ? safe.String_split.call(rawNeedlePaths, / +/) : []; if ( stackNeedleDetails.matchAll !== true ) { - if ( matchesStackTrace(stackNeedleDetails, extraArgs.logstack) === false ) { + if ( matchesStackTraceFn(stackNeedleDetails, extraArgs.logstack) === false ) { return; } } @@ -909,208 +529,15 @@ function objectFindOwnerFn( /******************************************************************************/ -builtinScriptlets.push({ - name: 'get-all-cookies.fn', - fn: getAllCookiesFn, -}); -function getAllCookiesFn() { - return document.cookie.split(/\s*;\s*/).map(s => { - const pos = s.indexOf('='); - if ( pos === 0 ) { return; } - if ( pos === -1 ) { return `${s.trim()}=`; } - const key = s.slice(0, pos).trim(); - const value = s.slice(pos+1).trim(); - return { key, value }; - }).filter(s => s !== undefined); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'get-all-local-storage.fn', - fn: getAllLocalStorageFn, -}); -function getAllLocalStorageFn(which = 'localStorage') { - const storage = self[which]; - const out = []; - for ( let i = 0; i < storage.length; i++ ) { - const key = storage.key(i); - const value = storage.getItem(key); - return { key, value }; - } - return out; -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'get-cookie.fn', - fn: getCookieFn, -}); -function getCookieFn( - name = '' -) { - for ( const s of document.cookie.split(/\s*;\s*/) ) { - const pos = s.indexOf('='); - if ( pos === -1 ) { continue; } - if ( s.slice(0, pos) !== name ) { continue; } - return s.slice(pos+1).trim(); - } -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'set-cookie.fn', - fn: setCookieFn, - dependencies: [ - 'get-cookie.fn', - ], -}); -function setCookieFn( - trusted = false, - name = '', - value = '', - expires = '', - path = '', - options = {}, -) { - // https://datatracker.ietf.org/doc/html/rfc2616#section-2.2 - // https://github.com/uBlockOrigin/uBlock-issues/issues/2777 - if ( trusted === false && /[^!#$%&'*+\-.0-9A-Z[\]^_`a-z|~]/.test(name) ) { - name = encodeURIComponent(name); - } - // https://datatracker.ietf.org/doc/html/rfc6265#section-4.1.1 - // The characters [",] are given a pass from the RFC requirements because - // apparently browsers do not follow the RFC to the letter. - if ( /[^ -:<-[\]-~]/.test(value) ) { - value = encodeURIComponent(value); - } - - const cookieBefore = getCookieFn(name); - if ( cookieBefore !== undefined && options.dontOverwrite ) { return; } - if ( cookieBefore === value && options.reload ) { return; } - - const cookieParts = [ name, '=', value ]; - if ( expires !== '' ) { - cookieParts.push('; expires=', expires); - } - - if ( path === '' ) { path = '/'; } - else if ( path === 'none' ) { path = ''; } - if ( path !== '' && path !== '/' ) { return; } - if ( path === '/' ) { - cookieParts.push('; path=/'); - } - - if ( trusted ) { - if ( options.domain ) { - cookieParts.push(`; domain=${options.domain}`); - } - cookieParts.push('; Secure'); - } - - try { - document.cookie = cookieParts.join(''); - } catch(_) { - } - - const done = getCookieFn(name) === value; - if ( done && options.reload ) { - window.location.reload(); - } - - return done; -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'set-local-storage-item.fn', - fn: setLocalStorageItemFn, - dependencies: [ - 'safe-self.fn', - ], -}); -function setLocalStorageItemFn( - which = 'local', - trusted = false, - key = '', - value = '', -) { - if ( key === '' ) { return; } - - // For increased compatibility with AdGuard - if ( value === 'emptyArr' ) { - value = '[]'; - } else if ( value === 'emptyObj' ) { - value = '{}'; - } - - const trustedValues = [ - '', - 'undefined', 'null', - 'false', 'true', - 'on', 'off', - 'yes', 'no', - 'accept', 'reject', - 'accepted', 'rejected', - '{}', '[]', '""', - '$remove$', - ]; - - if ( trusted ) { - if ( value.includes('$now$') ) { - value = value.replaceAll('$now$', Date.now()); - } - if ( value.includes('$currentDate$') ) { - value = value.replaceAll('$currentDate$', `${Date()}`); - } - if ( value.includes('$currentISODate$') ) { - value = value.replaceAll('$currentISODate$', (new Date()).toISOString()); - } - } else { - const normalized = value.toLowerCase(); - const match = /^("?)(.+)\1$/.exec(normalized); - const unquoted = match && match[2] || normalized; - if ( trustedValues.includes(unquoted) === false ) { - if ( /^\d+$/.test(unquoted) === false ) { return; } - const n = parseInt(unquoted, 10); - if ( n > 32767 ) { return; } - } - } - - try { - const storage = self[`${which}Storage`]; - if ( value === '$remove$' ) { - const safe = safeSelf(); - const pattern = safe.patternToRegex(key, undefined, true ); - const toRemove = []; - for ( let i = 0, n = storage.length; i < n; i++ ) { - const key = storage.key(i); - if ( pattern.test(key) ) { toRemove.push(key); } - } - for ( const key of toRemove ) { - storage.removeItem(key); - } - } else { - storage.setItem(key, `${value}`); - } - } catch(ex) { - } -} - -/******************************************************************************/ - builtinScriptlets.push({ name: 'matches-stack-trace.fn', - fn: matchesStackTrace, + fn: matchesStackTraceFn, dependencies: [ 'get-exception-token.fn', 'safe-self.fn', ], }); -function matchesStackTrace( +function matchesStackTraceFn( needleDetails, logLevel = '' ) { @@ -1122,7 +549,7 @@ function matchesStackTrace( // Normalize stack trace const reLine = /(.*?@)?(\S+)(:\d+):\d+\)?$/; const lines = []; - for ( let line of error.stack.split(/[\n\r]+/) ) { + 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); @@ -1169,8 +596,8 @@ function parsePropertiesToMatch(propsToMatch, implicit = '') { const needles = new Map(); if ( propsToMatch === undefined || propsToMatch === '' ) { return needles; } const options = { canNegate: true }; - for ( const needle of propsToMatch.split(/\s+/) ) { - const [ prop, pattern ] = needle.split(':'); + for ( const needle of safe.String_split.call(propsToMatch, /\s+/) ) { + const [ prop, pattern ] = safe.String_split.call(needle, ':'); if ( prop === '' ) { continue; } if ( pattern !== undefined ) { needles.set(prop, safe.initPattern(pattern, options)); @@ -1332,6 +759,8 @@ function replaceFetchResponseFn( if ( pattern === '*' ) { pattern = '.*'; } const rePattern = safe.patternToRegex(pattern); const propNeedles = parsePropertiesToMatch(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); @@ -1361,6 +790,9 @@ function replaceFetchResponseFn( return fetchPromise.then(responseBefore => { const response = responseBefore.clone(); return response.text().then(textBefore => { + if ( reIncludes && reIncludes.test(textBefore) === false ) { + return responseBefore; + } const textAfter = textBefore.replace(rePattern, replacement); const outcome = textAfter !== textBefore ? 'match' : 'nomatch'; if ( outcome === 'nomatch' ) { return responseBefore; } @@ -1392,38 +824,198 @@ function replaceFetchResponseFn( /******************************************************************************/ builtinScriptlets.push({ - name: 'proxy-apply.fn', - fn: proxyApplyFn, + name: 'prevent-xhr.fn', + fn: preventXhrFn, dependencies: [ + 'generate-content.fn', + 'match-object-properties.fn', + 'parse-properties-to-match.fn', 'safe-self.fn', ], }); -function proxyApplyFn( - target = '', - handler = '' +function preventXhrFn( + trusted = false, + propsToMatch = '', + directive = '' ) { - let context = globalThis; - let prop = target; - 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); - } - const fn = context[prop]; - if ( typeof fn !== 'function' ) { return; } - if ( fn.prototype && fn.prototype.constructor === fn ) { - context[prop] = new Proxy(fn, { construct: handler }); - return (...args) => { return Reflect.construct(...args); }; - } - context[prop] = new Proxy(fn, { apply: handler }); - return (...args) => { return Reflect.apply(...args); }; -} - -/******************************************************************************* - - Injectable scriptlets + if ( typeof propsToMatch !== 'string' ) { return; } + const safe = safeSelf(); + 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 warOrigin = scriptletGlobals.warOrigin; + const safeDispatchEvent = (xhr, type) => { + try { + xhr.dispatchEvent(new Event(type)); + } catch(_) { + } + }; + const XHRBefore = XMLHttpRequest.prototype; + self.XMLHttpRequest = class extends self.XMLHttpRequest { + open(method, url, ...args) { + xhrInstances.delete(this); + if ( warOrigin !== undefined && url.startsWith(warOrigin) ) { + return super.open(method, url, ...args); + } + const haystack = { method, url }; + if ( propsToMatch === '' && directive === '' ) { + safe.uboLog(logPrefix, `Called: ${safe.JSON_stringify(haystack, null, 2)}`); + return super.open(method, url, ...args); + } + if ( matchObjectProperties(propNeedles, haystack) ) { + const xhrDetails = Object.assign(haystack, { + xhr: this, + defer: args.length === 0 || !!args[0], + directive, + headers: { + 'date': '', + 'content-type': '', + 'content-length': '', + }, + url: haystack.url, + props: { + response: { value: '' }, + responseText: { value: '' }, + responseXML: { value: null }, + }, + }); + xhrInstances.set(this, xhrDetails); + } + return super.open(method, url, ...args); + } + send(...args) { + const xhrDetails = xhrInstances.get(this); + if ( xhrDetails === undefined ) { + return super.send(...args); + } + xhrDetails.headers['date'] = (new Date()).toUTCString(); + let xhrText = ''; + switch ( this.responseType ) { + case 'arraybuffer': + xhrDetails.props.response.value = new ArrayBuffer(0); + xhrDetails.headers['content-type'] = 'application/octet-stream'; + break; + case 'blob': + xhrDetails.props.response.value = new Blob([]); + xhrDetails.headers['content-type'] = 'application/octet-stream'; + break; + case 'document': { + const parser = new DOMParser(); + const doc = parser.parseFromString('', 'text/html'); + xhrDetails.props.response.value = doc; + xhrDetails.props.responseXML.value = doc; + xhrDetails.headers['content-type'] = 'text/html'; + break; + } + case 'json': + xhrDetails.props.response.value = {}; + xhrDetails.props.responseText.value = '{}'; + xhrDetails.headers['content-type'] = 'application/json'; + break; + default: { + if ( directive === '' ) { break; } + xhrText = generateContentFn(trusted, xhrDetails.directive); + if ( xhrText instanceof Promise ) { + xhrText = xhrText.then(text => { + xhrDetails.props.response.value = text; + xhrDetails.props.responseText.value = text; + }); + } else { + xhrDetails.props.response.value = xhrText; + xhrDetails.props.responseText.value = xhrText; + } + xhrDetails.headers['content-type'] = 'text/plain'; + break; + } + } + if ( xhrDetails.defer === false ) { + xhrDetails.headers['content-length'] = `${xhrDetails.props.response.value}`.length; + Object.defineProperties(xhrDetails.xhr, { + readyState: { value: 4 }, + responseURL: { value: xhrDetails.url }, + status: { value: 200 }, + statusText: { value: 'OK' }, + }); + Object.defineProperties(xhrDetails.xhr, xhrDetails.props); + return; + } + Promise.resolve(xhrText).then(( ) => xhrDetails).then(details => { + Object.defineProperties(details.xhr, { + readyState: { value: 1, configurable: true }, + responseURL: { value: xhrDetails.url }, + }); + safeDispatchEvent(details.xhr, 'readystatechange'); + return details; + }).then(details => { + xhrDetails.headers['content-length'] = `${details.props.response.value}`.length; + Object.defineProperties(details.xhr, { + readyState: { value: 2, configurable: true }, + status: { value: 200 }, + statusText: { value: 'OK' }, + }); + safeDispatchEvent(details.xhr, 'readystatechange'); + return details; + }).then(details => { + Object.defineProperties(details.xhr, { + readyState: { value: 3, configurable: true }, + }); + Object.defineProperties(details.xhr, details.props); + safeDispatchEvent(details.xhr, 'readystatechange'); + return details; + }).then(details => { + Object.defineProperties(details.xhr, { + readyState: { value: 4 }, + }); + safeDispatchEvent(details.xhr, 'readystatechange'); + safeDispatchEvent(details.xhr, 'load'); + safeDispatchEvent(details.xhr, 'loadend'); + safe.uboLog(logPrefix, `Prevented with response:\n${details.xhr.response}`); + }); + } + getResponseHeader(headerName) { + const xhrDetails = xhrInstances.get(this); + if ( xhrDetails === undefined || this.readyState < this.HEADERS_RECEIVED ) { + return super.getResponseHeader(headerName); + } + const value = xhrDetails.headers[headerName.toLowerCase()]; + if ( value !== undefined && value !== '' ) { return value; } + return null; + } + getAllResponseHeaders() { + const xhrDetails = xhrInstances.get(this); + if ( xhrDetails === undefined || this.readyState < this.HEADERS_RECEIVED ) { + return super.getAllResponseHeaders(); + } + const out = []; + for ( const [ name, value ] of Object.entries(xhrDetails.headers) ) { + if ( !value ) { continue; } + out.push(`${name}: ${value}`); + } + if ( out.length !== 0 ) { out.push(''); } + return out.join('\r\n'); + } + }; + self.XMLHttpRequest.prototype.open.toString = function() { + return XHRBefore.open.toString(); + }; + self.XMLHttpRequest.prototype.send.toString = function() { + return XHRBefore.send.toString(); + }; + self.XMLHttpRequest.prototype.getResponseHeader.toString = function() { + return XHRBefore.getResponseHeader.toString(); + }; + self.XMLHttpRequest.prototype.getAllResponseHeaders.toString = function() { + return XHRBefore.getAllResponseHeaders.toString(); + }; +} + + + + +/******************************************************************************* + + Injectable scriptlets These are meant to be used in the MAIN (webpage) execution world. @@ -1577,13 +1169,13 @@ function abortOnStackTrace( let v = owner[chain]; Object.defineProperty(owner, chain, { get: function() { - if ( matchesStackTrace(needleDetails, extraArgs.log) ) { + if ( matchesStackTraceFn(needleDetails, extraArgs.log) ) { throw new ReferenceError(getExceptionToken()); } return v; }, set: function(a) { - if ( matchesStackTrace(needleDetails, extraArgs.log) ) { + if ( matchesStackTraceFn(needleDetails, extraArgs.log) ) { throw new ReferenceError(getExceptionToken()); } v = a; @@ -1624,6 +1216,7 @@ builtinScriptlets.push({ ], fn: addEventListenerDefuser, dependencies: [ + 'proxy-apply.fn', 'run-at.fn', 'safe-self.fn', 'should-debug.fn', @@ -1642,6 +1235,8 @@ function addEventListenerDefuser( const debug = shouldDebug(extraArgs); const targetSelector = extraArgs.elements || undefined; const elementMatches = elem => { + if ( targetSelector === 'window' ) { return elem === window; } + if ( targetSelector === 'document' ) { return elem === document; } if ( elem && elem.matches && elem.matches(targetSelector) ) { return true; } const elems = Array.from(document.querySelectorAll(targetSelector)); return elems.includes(elem); @@ -1651,7 +1246,9 @@ function addEventListenerDefuser( if ( elem instanceof Document ) { return 'document'; } if ( elem instanceof Element === false ) { return '?'; } const parts = []; - if ( elem.id !== '' ) { parts.push(`#${CSS.escape(elem.id)}`); } + // https://github.com/uBlockOrigin/uAssets/discussions/17907#discussioncomment-9871079 + const id = String(elem.id); + if ( id !== '' ) { parts.push(`#${CSS.escape(id)}`); } for ( let i = 0; i < elem.classList.length; i++ ) { parts.push(`.${CSS.escape(elem.classList.item(i))}`); } @@ -1676,44 +1273,30 @@ function addEventListenerDefuser( } return matchesBoth; }; - const trapEddEventListeners = ( ) => { - const eventListenerHandler = { - apply: function(target, thisArg, args) { - let t, h; - try { - t = String(args[0]); - if ( typeof args[1] === 'function' ) { - h = String(safe.Function_toString(args[1])); - } else if ( typeof args[1] === 'object' && args[1] !== null ) { - if ( typeof args[1].handleEvent === 'function' ) { - h = String(safe.Function_toString(args[1].handleEvent)); - } - } else { - h = String(args[1]); + 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)); } - } 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 Reflect.apply(target, thisArg, args); - }, - get(target, prop, receiver) { - if ( prop === 'toString' ) { - return target.toString.bind(target); + } else { + h = String(callArgs[1]); } - return Reflect.get(target, prop, receiver); - }, - }; - self.EventTarget.prototype.addEventListener = new Proxy( - self.EventTarget.prototype.addEventListener, - eventListenerHandler - ); - }; - runAt(( ) => { - trapEddEventListeners(); + } 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); } @@ -2050,18 +1633,19 @@ builtinScriptlets.push({ fn: noFetchIf, dependencies: [ 'generate-content.fn', + 'proxy-apply.fn', 'safe-self.fn', ], }); function noFetchIf( propsToMatch = '', - responseBody = '' + responseBody = '', + responseType = '' ) { - if ( typeof propsToMatch !== 'string' ) { return; } const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('prevent-fetch', propsToMatch, responseBody); + const logPrefix = safe.makeLogPrefix('prevent-fetch', propsToMatch, responseBody, responseType); const needles = []; - for ( const condition of propsToMatch.split(/\s+/) ) { + for ( const condition of safe.String_split.call(propsToMatch, /\s+/) ) { if ( condition === '' ) { continue; } const pos = condition.indexOf(':'); let key, value; @@ -2072,75 +1656,83 @@ function noFetchIf( key = 'url'; value = condition; } - needles.push({ key, re: safe.patternToRegex(value) }); + needles.push({ key, pattern: safe.initPattern(value, { canNegate: true }) }); } - self.fetch = new Proxy(self.fetch, { - apply: function(target, thisArg, args) { - const details = args[0] instanceof self.Request - ? args[0] - : Object.assign({ url: args[0] }, args[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 ( propsToMatch === '' && responseBody === '' ) { - const out = Array.from(props).map(a => `${a[0]}:${a[1]}`); - safe.uboLog(logPrefix, `Called: ${out.join('\n')}`); - return Reflect.apply(target, thisArg, args); - } - proceed = needles.length === 0; - for ( const { key, re } of needles ) { - if ( - props.has(key) === false || - re.test(props.get(key)) === false - ) { - proceed = true; - break; - } + 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) { } } - } catch(ex) { + if ( typeof v !== 'string' ) { continue; } + props.set(prop, v); } - if ( proceed ) { - return Reflect.apply(target, thisArg, args); + if ( safe.logLevel > 1 || propsToMatch === '' && responseBody === '' ) { + const out = Array.from(props).map(a => `${a[0]}:${a[1]}`); + safe.uboLog(logPrefix, `Called: ${out.join('\n')}`); } - let responseType = ''; - if ( details.mode === undefined || details.mode === 'cors' ) { - try { - const desURL = new URL(details.url); - responseType = desURL.origin !== document.location.origin - ? 'cors' - : 'basic'; - } catch(ex) { - safe.uboErr(logPrefix, `Error: ${ex}`); + 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; } } - return generateContentFn(responseBody).then(text => { - safe.uboLog(logPrefix, `Prevented with response "${text}"`); - const response = new Response(text, { - statusText: 'OK', - headers: { - 'Content-Length': text.length, - } - }); - safe.Object_defineProperty(response, 'url', { - value: details.url - }); - if ( responseType !== '' ) { - safe.Object_defineProperty(response, 'type', { - value: responseType - }); + } 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, } - return response; }); - } + const props = Object.assign( + { url: { value: details.url } }, + responseProps + ); + safe.Object_defineProperties(response, props); + return response; + }); }); } @@ -2154,106 +1746,34 @@ builtinScriptlets.push({ fn: preventRefresh, world: 'ISOLATED', dependencies: [ - 'run-at.fn', 'safe-self.fn', ], }); // https://www.reddit.com/r/uBlockOrigin/comments/q0frv0/while_reading_a_sports_article_i_was_redirected/hf7wo9v/ function preventRefresh( - arg1 = '' + delay = '' ) { - if ( typeof arg1 !== 'string' ) { return; } + if ( typeof delay !== 'string' ) { return; } const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('prevent-refresh', arg1); + const logPrefix = safe.makeLogPrefix('prevent-refresh', delay); + const stop = content => { + window.stop(); + safe.uboLog(logPrefix, `Prevented "${content}"`); + }; const defuse = ( ) => { const meta = document.querySelector('meta[http-equiv="refresh" i][content]'); if ( meta === null ) { return; } - safe.uboLog(logPrefix, `Prevented "${meta.textContent}"`); - const s = arg1 === '' - ? meta.getAttribute('content') - : arg1; - const ms = Math.max(parseFloat(s) || 0, 0) * 1000; - setTimeout(( ) => { window.stop(); }, ms); - }; - runAt(( ) => { - defuse(); - }, 'interactive'); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'remove-attr.js', - aliases: [ - 'ra.js', - ], - fn: removeAttr, - dependencies: [ - 'run-at.fn', - 'safe-self.fn', - ], -}); -function removeAttr( - rawToken = '', - rawSelector = '', - behavior = '' -) { - if ( typeof rawToken !== 'string' ) { return; } - if ( rawToken === '' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('remove-attr', rawToken, rawSelector, behavior); - const tokens = rawToken.split(/\s*\|\s*/); - const selector = tokens - .map(a => `${rawSelector}[${CSS.escape(a)}]`) - .join(','); - if ( safe.logLevel > 1 ) { - safe.uboLog(logPrefix, `Target selector:\n\t${selector}`); - } - let timer; - const rmattr = ( ) => { - timer = undefined; - try { - const nodes = document.querySelectorAll(selector); - for ( const node of nodes ) { - for ( const attr of tokens ) { - if ( node.hasAttribute(attr) === false ) { continue; } - node.removeAttribute(attr); - safe.uboLog(logPrefix, `Removed attribute '${attr}'`); - } - } - } catch(ex) { - } - }; - const mutationHandler = mutations => { - if ( timer !== undefined ) { return; } - let skip = true; - for ( let i = 0; i < mutations.length && skip; i++ ) { - const { type, addedNodes, removedNodes } = mutations[i]; - if ( type === 'attributes' ) { skip = false; } - for ( let j = 0; j < addedNodes.length && skip; j++ ) { - if ( addedNodes[j].nodeType === 1 ) { skip = false; break; } - } - for ( let j = 0; j < removedNodes.length && skip; j++ ) { - if ( removedNodes[j].nodeType === 1 ) { skip = false; break; } - } + const content = meta.getAttribute('content') || ''; + const ms = delay === '' + ? Math.max(parseFloat(content) || 0, 0) * 500 + : 0; + if ( ms === 0 ) { + stop(content); + } else { + setTimeout(( ) => { stop(content); }, ms); } - if ( skip ) { return; } - timer = safe.onIdle(rmattr, { timeout: 67 }); - }; - const start = ( ) => { - rmattr(); - if ( /\bstay\b/.test(behavior) === false ) { return; } - const observer = new MutationObserver(mutationHandler); - observer.observe(document, { - attributes: true, - attributeFilter: tokens, - childList: true, - subtree: true, - }); }; - runAt(( ) => { - start(); - }, /\bcomplete\b/.test(behavior) ? 'idle' : 'interactive'); + self.addEventListener('load', defuse, { capture: true, once: true }); } /******************************************************************************/ @@ -2279,7 +1799,7 @@ function removeClass( if ( rawToken === '' ) { return; } const safe = safeSelf(); const logPrefix = safe.makeLogPrefix('remove-class', rawToken, rawSelector, behavior); - const tokens = rawToken.split(/\s*\|\s*/); + const tokens = safe.String_split.call(rawToken, /\s*\|\s*/); const selector = tokens .map(a => `${rawSelector}.${CSS.escape(a)}`) .join(','); @@ -2336,227 +1856,42 @@ function removeClass( /******************************************************************************/ builtinScriptlets.push({ - name: 'no-requestAnimationFrame-if.js', - aliases: [ - 'norafif.js', - 'prevent-requestAnimationFrame.js', - ], - fn: noRequestAnimationFrameIf, + name: 'webrtc-if.js', + fn: webrtcIf, dependencies: [ 'safe-self.fn', ], }); -function noRequestAnimationFrameIf( - needle = '' +function webrtcIf( + good = '' ) { - if ( typeof needle !== 'string' ) { return; } + if ( typeof good !== 'string' ) { return; } const safe = safeSelf(); - const needleNot = needle.charAt(0) === '!'; - if ( needleNot ) { needle = needle.slice(1); } - const log = needleNot === false && needle === '' ? console.log : undefined; - const reNeedle = safe.patternToRegex(needle); - window.requestAnimationFrame = new Proxy(window.requestAnimationFrame, { - apply: function(target, thisArg, args) { - const a = args[0] instanceof Function - ? String(safe.Function_toString(args[0])) - : String(args[0]); - let defuse = false; - if ( log !== undefined ) { - log('uBO: requestAnimationFrame("%s")', a); - } else { - defuse = reNeedle.test(a) !== needleNot; + const reGood = safe.patternToRegex(good); + const rtcName = window.RTCPeerConnection + ? 'RTCPeerConnection' + : (window.webkitRTCPeerConnection ? 'webkitRTCPeerConnection' : ''); + if ( rtcName === '' ) { return; } + const log = console.log.bind(console); + const neuteredPeerConnections = new WeakSet(); + const isGoodConfig = function(instance, config) { + if ( neuteredPeerConnections.has(instance) ) { return false; } + if ( config instanceof Object === false ) { return true; } + if ( Array.isArray(config.iceServers) === false ) { return true; } + for ( const server of config.iceServers ) { + const urls = typeof server.urls === 'string' + ? [ server.urls ] + : server.urls; + if ( Array.isArray(urls) ) { + for ( const url of urls ) { + if ( reGood.test(url) ) { return true; } + } + } + if ( typeof server.username === 'string' ) { + if ( reGood.test(server.username) ) { return true; } } - if ( defuse ) { - args[0] = function(){}; - } - return target.apply(thisArg, args); - } - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'set-constant.js', - aliases: [ - 'set.js', - ], - fn: setConstant, - dependencies: [ - 'set-constant.fn' - ], -}); -function setConstant( - ...args -) { - setConstantFn(false, ...args); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'no-setInterval-if.js', - aliases: [ - 'nosiif.js', - 'prevent-setInterval.js', - 'setInterval-defuser.js', - ], - fn: noSetIntervalIf, - dependencies: [ - 'safe-self.fn', - ], -}); -function noSetIntervalIf( - needle = '', - delay = '' -) { - if ( typeof needle !== 'string' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('prevent-setInterval', needle, delay); - const needleNot = needle.charAt(0) === '!'; - if ( needleNot ) { needle = needle.slice(1); } - if ( delay === '' ) { delay = undefined; } - let delayNot = false; - if ( delay !== undefined ) { - delayNot = delay.charAt(0) === '!'; - if ( delayNot ) { delay = delay.slice(1); } - delay = parseInt(delay, 10); - } - const reNeedle = safe.patternToRegex(needle); - self.setInterval = new Proxy(self.setInterval, { - apply: function(target, thisArg, args) { - const a = args[0] instanceof Function - ? String(safe.Function_toString(args[0])) - : String(args[0]); - const b = args[1]; - if ( needle === '' && delay === undefined ) { - safe.uboLog(logPrefix, `Called:\n${a}\n${b}`); - return Reflect.apply(target, thisArg, args); - } - let defuse; - if ( needle !== '' ) { - defuse = reNeedle.test(a) !== needleNot; - } - if ( defuse !== false && delay !== undefined ) { - defuse = (b === delay || isNaN(b) && isNaN(delay) ) !== delayNot; - } - if ( defuse ) { - args[0] = function(){}; - safe.uboLog(logPrefix, `Prevented:\n${a}\n${b}`); - } - return Reflect.apply(target, thisArg, args); - }, - get(target, prop, receiver) { - if ( prop === 'toString' ) { - return target.toString.bind(target); - } - return Reflect.get(target, prop, receiver); - }, - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'no-setTimeout-if.js', - aliases: [ - 'nostif.js', - 'prevent-setTimeout.js', - 'setTimeout-defuser.js', - ], - fn: noSetTimeoutIf, - dependencies: [ - 'safe-self.fn', - ], -}); -function noSetTimeoutIf( - needle = '', - delay = '' -) { - if ( typeof needle !== 'string' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('prevent-setTimeout', needle, delay); - const needleNot = needle.charAt(0) === '!'; - if ( needleNot ) { needle = needle.slice(1); } - if ( delay === '' ) { delay = undefined; } - let delayNot = false; - if ( delay !== undefined ) { - delayNot = delay.charAt(0) === '!'; - if ( delayNot ) { delay = delay.slice(1); } - delay = parseInt(delay, 10); - } - const reNeedle = safe.patternToRegex(needle); - self.setTimeout = new Proxy(self.setTimeout, { - apply: function(target, thisArg, args) { - const a = args[0] instanceof Function - ? String(safe.Function_toString(args[0])) - : String(args[0]); - const b = args[1]; - if ( needle === '' && delay === undefined ) { - safe.uboLog(logPrefix, `Called:\n${a}\n${b}`); - return Reflect.apply(target, thisArg, args); - } - let defuse; - if ( needle !== '' ) { - defuse = reNeedle.test(a) !== needleNot; - } - if ( defuse !== false && delay !== undefined ) { - defuse = (b === delay || isNaN(b) && isNaN(delay) ) !== delayNot; - } - if ( defuse ) { - args[0] = function(){}; - safe.uboLog(logPrefix, `Prevented:\n${a}\n${b}`); - } - return Reflect.apply(target, thisArg, args); - }, - get(target, prop, receiver) { - if ( prop === 'toString' ) { - return target.toString.bind(target); - } - return Reflect.get(target, prop, receiver); - }, - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'webrtc-if.js', - fn: webrtcIf, - dependencies: [ - 'safe-self.fn', - ], -}); -function webrtcIf( - good = '' -) { - if ( typeof good !== 'string' ) { return; } - const safe = safeSelf(); - const reGood = safe.patternToRegex(good); - const rtcName = window.RTCPeerConnection - ? 'RTCPeerConnection' - : (window.webkitRTCPeerConnection ? 'webkitRTCPeerConnection' : ''); - if ( rtcName === '' ) { return; } - const log = console.log.bind(console); - const neuteredPeerConnections = new WeakSet(); - const isGoodConfig = function(instance, config) { - if ( neuteredPeerConnections.has(instance) ) { return false; } - if ( config instanceof Object === false ) { return true; } - if ( Array.isArray(config.iceServers) === false ) { return true; } - for ( const server of config.iceServers ) { - const urls = typeof server.urls === 'string' - ? [ server.urls ] - : server.urls; - if ( Array.isArray(urls) ) { - for ( const url of urls ) { - if ( reGood.test(url) ) { return true; } - } - } - if ( typeof server.username === 'string' ) { - if ( reGood.test(server.username) ) { return true; } - } - if ( typeof server.credential === 'string' ) { - if ( reGood.test(server.credential) ) { return true; } + if ( typeof server.credential === 'string' ) { + if ( reGood.test(server.credential) ) { return true; } } } neuteredPeerConnections.add(instance); @@ -2589,160 +1924,63 @@ function webrtcIf( /******************************************************************************/ builtinScriptlets.push({ - name: 'no-xhr-if.js', + name: 'prevent-xhr.js', aliases: [ - 'prevent-xhr.js', + 'no-xhr-if.js', ], - fn: noXhrIf, + fn: preventXhr, dependencies: [ - 'generate-content.fn', - 'match-object-properties.fn', - 'parse-properties-to-match.fn', - 'safe-self.fn', + 'prevent-xhr.fn', ], }); -function noXhrIf( - propsToMatch = '', - directive = '' -) { - if ( typeof propsToMatch !== 'string' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('prevent-xhr', propsToMatch, directive); - const xhrInstances = new WeakMap(); - const propNeedles = parsePropertiesToMatch(propsToMatch, 'url'); - const warOrigin = scriptletGlobals.warOrigin; - const headers = { - 'date': '', - 'content-type': '', - 'content-length': '', - }; - self.XMLHttpRequest = class extends self.XMLHttpRequest { - open(method, url, ...args) { - xhrInstances.delete(this); - if ( warOrigin !== undefined && url.startsWith(warOrigin) ) { - return super.open(method, url, ...args); - } - const haystack = { method, url }; - if ( propsToMatch === '' && directive === '' ) { - safe.uboLog(logPrefix, `Called: ${safe.JSON_stringify(haystack, null, 2)}`); - return super.open(method, url, ...args); - } - if ( matchObjectProperties(propNeedles, haystack) ) { - xhrInstances.set(this, haystack); - } - haystack.headers = Object.assign({}, headers); - return super.open(method, url, ...args); - } - send(...args) { - const haystack = xhrInstances.get(this); - if ( haystack === undefined ) { - return super.send(...args); - } - haystack.headers['date'] = (new Date()).toUTCString(); - let promise = Promise.resolve({ - xhr: this, - directive, - props: { - readyState: { value: 4 }, - response: { value: '' }, - responseText: { value: '' }, - responseXML: { value: null }, - responseURL: { value: haystack.url }, - status: { value: 200 }, - statusText: { value: 'OK' }, - }, - }); - switch ( this.responseType ) { - case 'arraybuffer': - promise = promise.then(details => { - details.props.response.value = new ArrayBuffer(0); - return details; - }); - haystack.headers['content-type'] = 'application/octet-stream'; - break; - case 'blob': - promise = promise.then(details => { - details.props.response.value = new Blob([]); - return details; - }); - haystack.headers['content-type'] = 'application/octet-stream'; - break; - case 'document': { - promise = promise.then(details => { - const parser = new DOMParser(); - const doc = parser.parseFromString('', 'text/html'); - details.props.response.value = doc; - details.props.responseXML.value = doc; - return details; - }); - haystack.headers['content-type'] = 'text/html'; - break; - } - case 'json': - promise = promise.then(details => { - details.props.response.value = {}; - details.props.responseText.value = '{}'; - return details; - }); - haystack.headers['content-type'] = 'application/json'; - break; - default: - if ( directive === '' ) { break; } - promise = promise.then(details => { - return generateContentFn(details.directive).then(text => { - details.props.response.value = text; - details.props.responseText.value = text; - return details; - }); - }); - haystack.headers['content-type'] = 'text/plain'; - break; - } - promise.then(details => { - haystack.headers['content-length'] = `${details.props.response.value}`.length; - Object.defineProperties(details.xhr, details.props); - details.xhr.dispatchEvent(new Event('readystatechange')); - details.xhr.dispatchEvent(new Event('load')); - details.xhr.dispatchEvent(new Event('loadend')); - safe.uboLog(logPrefix, `Prevented with response:\n${details.xhr.response}`); - }); - } - getResponseHeader(headerName) { - const haystack = xhrInstances.get(this); - if ( haystack === undefined || this.readyState < this.HEADERS_RECEIVED ) { - return super.getResponseHeader(headerName); - } - const value = haystack.headers[headerName.toLowerCase()]; - if ( value !== undefined && value !== '' ) { return value; } - return null; - } - getAllResponseHeaders() { - const haystack = xhrInstances.get(this); - if ( haystack === undefined || this.readyState < this.HEADERS_RECEIVED ) { - return super.getAllResponseHeaders(); - } - const out = []; - for ( const [ name, value ] of Object.entries(haystack.headers) ) { - if ( !value ) { continue; } - out.push(`${name}: ${value}`); - } - if ( out.length !== 0 ) { out.push(''); } - return out.join('\r\n'); - } - }; +function preventXhr(...args) { + return preventXhrFn(false, ...args); } -/******************************************************************************/ +/** + * @scriptlet prevent-window-open + * + * @description + * Prevent a webpage from opening new tabs through `window.open()`. + * + * @param pattern + * A plain string or regex to match against the `url` argument for the + * prevention to be triggered. If not provided, all calls to `window.open()` + * are prevented. + * If set to the special value `debug` *and* the logger is opened, the scriptlet + * will trigger a `debugger` statement and the prevention will not occur. + * + * @param [delay] + * If provided, a decoy will be created or opened, and this parameter states + * the number of seconds to wait for before the decoy is terminated, i.e. + * either removed from the DOM or closed. + * + * @param [decoy] + * A string representing the type of decoy to use: + * - `blank`: replace the `url` parameter with `about:blank` + * - `object`: create and append an `object` element to the DOM, and return + * its `contentWindow` property. + * - `frame`: create and append an `iframe` element to the DOM, and return + * its `contentWindow` property. + * + * @example + * ##+js(prevent-window-open, ads.example.com/) + * + * @example + * ##+js(prevent-window-open, ads.example.com/, 1, iframe) + * + * */ builtinScriptlets.push({ - name: 'no-window-open-if.js', + name: 'prevent-window-open.js', aliases: [ 'nowoif.js', - 'prevent-window-open.js', + 'no-window-open-if.js', 'window.open-defuser.js', ], fn: noWindowOpenIf, dependencies: [ + 'proxy-apply.fn', 'safe-self.fn', ], }); @@ -2758,10 +1996,8 @@ function noWindowOpenIf( pattern = pattern.slice(1); } const rePattern = safe.patternToRegex(pattern); - let autoRemoveAfter = parseInt(delay); - if ( isNaN(autoRemoveAfter) ) { - autoRemoveAfter = -1; - } + const autoRemoveAfter = (parseFloat(delay) || 0) * 1000; + const setTimeout = self.setTimeout; const createDecoy = function(tag, urlProp, url) { const decoyElem = document.createElement(tag); decoyElem[urlProp] = url; @@ -2770,54 +2006,67 @@ function noWindowOpenIf( decoyElem.style.setProperty('top','-1px', 'important'); decoyElem.style.setProperty('width','1px', 'important'); document.body.appendChild(decoyElem); - setTimeout(( ) => { decoyElem.remove(); }, autoRemoveAfter * 1000); + setTimeout(( ) => { decoyElem.remove(); }, autoRemoveAfter); return decoyElem; }; - window.open = new Proxy(window.open, { - apply: function(target, thisArg, args) { - const haystack = args.join(' '); - if ( rePattern.test(haystack) !== targetMatchResult ) { - if ( safe.logLevel > 1 ) { - safe.uboLog(logPrefix, `Allowed (${args.join(', ')})`); - } - return Reflect.apply(target, thisArg, args); - } - safe.uboLog(logPrefix, `Prevented (${args.join(', ')})`); - if ( autoRemoveAfter < 0 ) { return null; } - const decoyElem = decoy === 'obj' - ? createDecoy('object', 'data', ...args) - : createDecoy('iframe', 'src', ...args); - let popup = decoyElem.contentWindow; - if ( typeof popup === 'object' && popup !== null ) { - Object.defineProperty(popup, 'closed', { value: false }); - } else { - const noopFunc = (function(){}).bind(self); - popup = new Proxy(self, { - get: function(target, prop) { - if ( prop === 'closed' ) { return false; } - const r = Reflect.get(...arguments); - if ( typeof r === 'function' ) { return noopFunc; } - return target[prop]; - }, - set: function() { - return Reflect.set(...arguments); - }, - }); - } - if ( safe.logLevel !== 0 ) { - popup = new Proxy(popup, { - get: function(target, prop) { - safe.uboLog(logPrefix, 'window.open / get', prop, '===', target[prop]); - return Reflect.get(...arguments); - }, - set: function(target, prop, value) { - safe.uboLog(logPrefix, 'window.open / set', prop, '=', value); - return Reflect.set(...arguments); - }, - }); + const noopFunc = function(){}; + proxyApplyFn('open', function open(context) { + if ( pattern === 'debug' && safe.logLevel !== 0 ) { + debugger; // eslint-disable-line no-debugger + return context.reflect(); + } + const { callArgs } = context; + const haystack = callArgs.join(' '); + if ( rePattern.test(haystack) !== targetMatchResult ) { + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `Allowed (${callArgs.join(', ')})`); } - return popup; + return context.reflect(); + } + safe.uboLog(logPrefix, `Prevented (${callArgs.join(', ')})`); + if ( delay === '' ) { return null; } + if ( decoy === 'blank' ) { + callArgs[0] = 'about:blank'; + const r = context.reflect(); + setTimeout(( ) => { r.close(); }, autoRemoveAfter); + return r; } + const decoyElem = decoy === 'obj' + ? createDecoy('object', 'data', ...callArgs) + : createDecoy('iframe', 'src', ...callArgs); + let popup = decoyElem.contentWindow; + if ( typeof popup === 'object' && popup !== null ) { + Object.defineProperty(popup, 'closed', { value: false }); + } else { + popup = new Proxy(self, { + get: function(target, prop, ...args) { + if ( prop === 'closed' ) { return false; } + const r = Reflect.get(target, prop, ...args); + if ( typeof r === 'function' ) { return noopFunc; } + return r; + }, + set: function(...args) { + return Reflect.set(...args); + }, + }); + } + if ( safe.logLevel !== 0 ) { + popup = new Proxy(popup, { + get: function(target, prop, ...args) { + const r = Reflect.get(target, prop, ...args); + safe.uboLog(logPrefix, `popup / get ${prop} === ${r}`); + if ( typeof r === 'function' ) { + return (...args) => { return r.call(target, ...args); }; + } + return r; + }, + set: function(target, prop, value, ...args) { + safe.uboLog(logPrefix, `popup / set ${prop} = ${value}`); + return Reflect.set(target, prop, value, ...args); + }, + }); + } + return popup; }); } @@ -2943,11 +2192,11 @@ function alertBuster() { apply: function(a) { console.info(a); }, - get(target, prop, receiver) { + get(target, prop) { if ( prop === 'toString' ) { return target.toString.bind(target); } - return Reflect.get(target, prop, receiver); + return Reflect.get(target, prop); }, }); } @@ -3014,82 +2263,6 @@ function disableNewtabLinks() { /******************************************************************************/ -builtinScriptlets.push({ - name: 'remove-cookie.js', - aliases: [ - 'cookie-remover.js', - ], - fn: cookieRemover, - world: 'ISOLATED', - dependencies: [ - 'safe-self.fn', - ], -}); -// https://github.com/NanoAdblocker/NanoFilters/issues/149 -function cookieRemover( - needle = '' -) { - if ( typeof needle !== 'string' ) { return; } - const safe = safeSelf(); - const reName = safe.patternToRegex(needle); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 1); - const throttle = (fn, ms = 500) => { - if ( throttle.timer !== undefined ) { return; } - throttle.timer = setTimeout(( ) => { - throttle.timer = undefined; - fn(); - }, ms); - }; - const removeCookie = ( ) => { - document.cookie.split(';').forEach(cookieStr => { - const pos = cookieStr.indexOf('='); - if ( pos === -1 ) { return; } - 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; - let part2c, part2d; - const domain = document.domain; - if ( domain ) { - if ( domain !== document.location.hostname ) { - part2c = '; domain=.' + domain; - } - if ( domain.startsWith('www.') ) { - part2d = '; domain=' + domain.replace('www', ''); - } - } - const part3 = '; path=/'; - const part4 = '; Max-Age=-1000; expires=Thu, 01 Jan 1970 00:00:00 GMT'; - document.cookie = part1 + part4; - document.cookie = part1 + part2a + part4; - document.cookie = part1 + part2b + part4; - document.cookie = part1 + part3 + part4; - document.cookie = part1 + part2a + part3 + part4; - document.cookie = part1 + part2b + part3 + part4; - if ( part2c !== undefined ) { - document.cookie = part1 + part2c + part3 + part4; - } - if ( part2d !== undefined ) { - document.cookie = part1 + part2d + part3 + part4; - } - }); - }; - removeCookie(); - window.addEventListener('beforeunload', removeCookie); - if ( typeof extraArgs.when !== 'string' ) { return; } - const supportedEventTypes = [ 'scroll', 'keydown' ]; - const eventTypes = extraArgs.when.split(/\s/); - for ( const type of eventTypes ) { - if ( supportedEventTypes.includes(type) === false ) { continue; } - document.addEventListener(type, ( ) => { - throttle(removeCookie); - }, { passive: true }); - } -} - -/******************************************************************************/ - builtinScriptlets.push({ name: 'xml-prune.js', fn: xmlPrune, @@ -3214,6 +2387,9 @@ function xmlPrune( const serializer = new XMLSerializer(); const textout = serializer.serializeToString(thisArg.responseXML); Object.defineProperty(thisArg, 'responseText', { value: textout }); + if ( typeof thisArg.response === 'string' ) { + Object.defineProperty(thisArg, 'response', { value: textout }); + } return; } if ( @@ -3336,12 +2512,12 @@ function m3uPrune( } text = before.trim() + '\n' + after.trim(); reM3u.lastIndex = before.length + 1; - toLog.push('Discarding', ...discard.split(/\n+/).map(s => `\t${s}`)); + toLog.push('Discarding', ...safe.String_split.call(discard, /\n+/).map(s => `\t${s}`)); if ( reM3u.global === false ) { break; } } return text; } - const lines = text.split(/\n\r|\n|\r/); + const lines = safe.String_split.call(text, /\n\r|\n|\r/); for ( let i = 0; i < lines.length; i++ ) { if ( lines[i] === undefined ) { continue; } if ( pruneSpliceoutBlock(lines, i) ) { continue; } @@ -3465,7 +2641,7 @@ function hrefSanitizer( }; const validateURL = text => { if ( text === '' ) { return ''; } - if ( /[^\x21-\x7e]/.test(text) ) { return ''; } + if ( /[\x00-\x20\x7f]/.test(text) ) { return ''; } try { const url = new URL(text, document.location); return url.href; @@ -3473,17 +2649,29 @@ function hrefSanitizer( } 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)); } + if ( value.includes(' ') ) { + value = value.replace(/ /g, '%20'); + } + return value; + } catch(x) { + } + return href; + }; const extractText = (elem, source) => { if ( /^\[.*\]$/.test(source) ) { return elem.getAttribute(source.slice(1,-1).trim()) || ''; } if ( source.startsWith('?') ) { - try { - const url = new URL(elem.href, document.location); - return url.searchParams.get(source.slice(1)) || ''; - } catch(x) { - } - return ''; + return extractParam(elem.href, source); } if ( source === 'text' ) { return elem.textContent @@ -3572,13 +2760,17 @@ function hrefSanitizer( builtinScriptlets.push({ name: 'call-nothrow.js', fn: callNothrow, + dependencies: [ + 'safe-self.fn', + ], }); function callNothrow( chain = '' ) { if ( typeof chain !== 'string' ) { return; } if ( chain === '' ) { return; } - const parts = chain.split('.'); + const safe = safeSelf(); + const parts = safe.String_split.call(chain, '.'); let owner = window, prop; for (;;) { prop = parts.shift(); @@ -3597,377 +2789,29 @@ function callNothrow( } catch(ex) { } return r; - }, - }); -} - - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'spoof-css.js', - fn: spoofCSS, - dependencies: [ - 'safe-self.fn', - ], -}); -function spoofCSS( - selector, - ...args -) { - if ( typeof selector !== 'string' ) { return; } - if ( selector === '' ) { return; } - const toCamelCase = s => s.replace(/-[a-z]/g, s => s.charAt(1).toUpperCase()); - const propToValueMap = new Map(); - for ( let i = 0; i < args.length; i += 2 ) { - if ( typeof args[i+0] !== 'string' ) { break; } - if ( args[i+0] === '' ) { break; } - if ( typeof args[i+1] !== 'string' ) { break; } - propToValueMap.set(toCamelCase(args[i+0]), args[i+1]); - } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('spoof-css', selector, ...args); - const canDebug = scriptletGlobals.canDebug; - const shouldDebug = canDebug && propToValueMap.get('debug') || 0; - const instanceProperties = [ 'cssText', 'length', 'parentRule' ]; - const spoofStyle = (prop, real) => { - const normalProp = toCamelCase(prop); - const shouldSpoof = propToValueMap.has(normalProp); - const value = shouldSpoof ? propToValueMap.get(normalProp) : real; - if ( shouldSpoof ) { - safe.uboLog(logPrefix, `Spoofing ${prop} to ${value}`); - } - return value; - }; - const cloackFunc = (fn, thisArg, name) => { - const trap = fn.bind(thisArg); - Object.defineProperty(trap, 'name', { value: name }); - Object.defineProperty(trap, 'toString', { - value: ( ) => `function ${name}() { [native code] }` - }); - return trap; - }; - self.getComputedStyle = new Proxy(self.getComputedStyle, { - apply: function(target, thisArg, args) { - // eslint-disable-next-line no-debugger - if ( shouldDebug !== 0 ) { debugger; } - const style = Reflect.apply(target, thisArg, args); - const targetElements = new WeakSet(document.querySelectorAll(selector)); - if ( targetElements.has(args[0]) === false ) { return style; } - const proxiedStyle = new Proxy(style, { - get(target, prop, receiver) { - if ( typeof target[prop] === 'function' ) { - if ( prop === 'getPropertyValue' ) { - return cloackFunc(function getPropertyValue(prop) { - return spoofStyle(prop, target[prop]); - }, target, 'getPropertyValue'); - } - return cloackFunc(target[prop], target, prop); - } - if ( instanceProperties.includes(prop) ) { - return Reflect.get(target, prop); - } - return spoofStyle(prop, Reflect.get(target, prop, receiver)); - }, - getOwnPropertyDescriptor(target, prop) { - if ( propToValueMap.has(prop) ) { - return { - configurable: true, - enumerable: true, - value: propToValueMap.get(prop), - writable: true, - }; - } - return Reflect.getOwnPropertyDescriptor(target, prop); - }, - }); - return proxiedStyle; - }, - get(target, prop, receiver) { - if ( prop === 'toString' ) { - return target.toString.bind(target); - } - return Reflect.get(target, prop, receiver); - }, - }); - Element.prototype.getBoundingClientRect = new Proxy(Element.prototype.getBoundingClientRect, { - apply: function(target, thisArg, args) { - // eslint-disable-next-line no-debugger - if ( shouldDebug !== 0 ) { debugger; } - const rect = Reflect.apply(target, thisArg, args); - const targetElements = new WeakSet(document.querySelectorAll(selector)); - if ( targetElements.has(thisArg) === false ) { return rect; } - let { height, width } = rect; - if ( propToValueMap.has('width') ) { - width = parseFloat(propToValueMap.get('width')); - } - if ( propToValueMap.has('height') ) { - height = parseFloat(propToValueMap.get('height')); - } - return new self.DOMRect(rect.x, rect.y, width, height); - }, - get(target, prop, receiver) { - if ( prop === 'toString' ) { - return target.toString.bind(target); - } - return Reflect.get(target, prop, receiver); - }, - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'remove-node-text.js', - aliases: [ - 'rmnt.js', - ], - fn: removeNodeText, - world: 'ISOLATED', - dependencies: [ - 'replace-node-text.fn', - ], -}); -function removeNodeText( - nodeName, - condition, - ...extraArgs -) { - replaceNodeTextFn(nodeName, '', '', 'condition', condition || '', ...extraArgs); -} - -/******************************************************************************* - * - * set-cookie.js - * - * Set specified cookie to a specific value. - * - * Reference: - * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-cookie.js - * - **/ - -builtinScriptlets.push({ - name: 'set-cookie.js', - fn: setCookie, - world: 'ISOLATED', - dependencies: [ - 'safe-self.fn', - 'set-cookie.fn', - ], -}); -function setCookie( - name = '', - value = '', - path = '' -) { - if ( name === '' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('set-cookie', name, value, path); - - const validValues = [ - 'accept', 'reject', - 'accepted', 'rejected', 'notaccepted', - 'allow', 'deny', - 'allowed', 'disallow', - 'enable', 'disable', - 'enabled', 'disabled', - 'ok', - 'on', 'off', - 'true', 't', 'false', 'f', - 'yes', 'y', 'no', 'n', - 'necessary', 'required', - 'approved', 'disapproved', - ]; - const normalized = value.toLowerCase(); - const match = /^("?)(.+)\1$/.exec(normalized); - const unquoted = match && match[2] || normalized; - if ( validValues.includes(unquoted) === false ) { - if ( /^\d+$/.test(unquoted) === false ) { return; } - const n = parseInt(value, 10); - if ( n > 32767 ) { return; } - } - - const done = setCookieFn( - false, - name, - value, - '', - path, - safe.getExtraArgs(Array.from(arguments), 3) - ); - - if ( done ) { - safe.uboLog(logPrefix, 'Done'); - } -} - -// For compatibility with AdGuard -builtinScriptlets.push({ - name: 'set-cookie-reload.js', - fn: setCookieReload, - world: 'ISOLATED', - dependencies: [ - 'set-cookie.js', - ], -}); -function setCookieReload(name, value, path, ...args) { - setCookie(name, value, path, 'reload', '1', ...args); -} - -/******************************************************************************* - * - * set-local-storage-item.js - * set-session-storage-item.js - * - * Set a local/session storage entry to a specific, allowed value. - * - * Reference: - * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-local-storage-item.js - * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-session-storage-item.js - * - **/ - -builtinScriptlets.push({ - name: 'set-local-storage-item.js', - fn: setLocalStorageItem, - world: 'ISOLATED', - dependencies: [ - 'set-local-storage-item.fn', - ], -}); -function setLocalStorageItem(key = '', value = '') { - setLocalStorageItemFn('local', false, key, value); -} - -builtinScriptlets.push({ - name: 'set-session-storage-item.js', - fn: setSessionStorageItem, - world: 'ISOLATED', - dependencies: [ - 'set-local-storage-item.fn', - ], -}); -function setSessionStorageItem(key = '', value = '') { - setLocalStorageItemFn('session', false, key, value); -} - -/******************************************************************************* - * - * @scriptlet set-attr - * - * @description - * Sets the specified attribute on the specified elements. This scriptlet runs - * once when the page loads then afterward on DOM mutations. - - * Reference: https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-attr.js - * - * ### Syntax - * - * ```text - * example.org##+js(set-attr, selector, attr [, value]) - * ``` - * - * - `selector`: CSS selector of DOM elements for which the attribute `attr` - * must be modified. - * - `attr`: the name of the attribute to modify - * - `value`: the value to assign to the target attribute. Possible values: - * - `''`: empty string (default) - * - `true` - * - `false` - * - positive decimal integer 0 <= value < 32768 - * - `[other]`: copy the value from attribute `other` on the same element - * */ - -builtinScriptlets.push({ - name: 'set-attr.js', - fn: setAttr, - world: 'ISOLATED', - dependencies: [ - 'run-at.fn', - 'safe-self.fn', - ], -}); -function setAttr( - selector = '', - attr = '', - value = '' -) { - if ( selector === '' ) { return; } - if ( attr === '' ) { return; } - - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('set-attr', attr, value); - const validValues = [ '', 'false', 'true' ]; - let copyFrom = ''; - - if ( validValues.includes(value.toLowerCase()) === false ) { - if ( /^\d+$/.test(value) ) { - const n = parseInt(value, 10); - if ( n >= 32768 ) { return; } - value = `${n}`; - } else if ( /^\[.+\]$/.test(value) ) { - copyFrom = value.slice(1, -1); - } else { - return; - } - } - - const extractValue = elem => { - if ( copyFrom !== '' ) { - return elem.getAttribute(copyFrom) || ''; - } - return value; - }; - - const applySetAttr = ( ) => { - const elems = []; - try { - elems.push(...document.querySelectorAll(selector)); - } - catch(ex) { - return false; - } - for ( const elem of elems ) { - const before = elem.getAttribute(attr); - const after = extractValue(elem); - if ( after === before ) { continue; } - if ( after !== '' && /^on/i.test(attr) ) { - if ( attr.toLowerCase() in elem ) { continue; } - } - elem.setAttribute(attr, after); - safe.uboLog(logPrefix, `${attr}="${after}"`); - } - return true; - }; - let observer, timer; - const onDomChanged = mutations => { - if ( timer !== undefined ) { return; } - let shouldWork = false; - for ( const mutation of mutations ) { - if ( mutation.addedNodes.length === 0 ) { continue; } - for ( const node of mutation.addedNodes ) { - if ( node.nodeType !== 1 ) { continue; } - shouldWork = true; - break; - } - if ( shouldWork ) { break; } - } - if ( shouldWork === false ) { return; } - timer = self.requestAnimationFrame(( ) => { - timer = undefined; - applySetAttr(); - }); - }; - const start = ( ) => { - if ( applySetAttr() === false ) { return; } - observer = new MutationObserver(onDomChanged); - observer.observe(document.body, { - subtree: true, - childList: true, - }); - }; - runAt(( ) => { start(); }, 'idle'); + }, + }); +} + +/******************************************************************************/ + +builtinScriptlets.push({ + name: 'remove-node-text.js', + aliases: [ + 'rmnt.js', + ], + fn: removeNodeText, + world: 'ISOLATED', + dependencies: [ + 'replace-node-text.fn', + ], +}); +function removeNodeText( + nodeName, + includes, + ...extraArgs +) { + replaceNodeTextFn(nodeName, '', '', 'includes', includes || '', ...extraArgs); } /******************************************************************************* @@ -4057,57 +2901,6 @@ function multiup() { document.addEventListener('click', handler, { capture: true }); } -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'remove-cache-storage-item.js', - fn: removeCacheStorageItem, - world: 'ISOLATED', - dependencies: [ - 'safe-self.fn', - ], -}); -function removeCacheStorageItem( - cacheNamePattern = '', - requestPattern = '' -) { - if ( cacheNamePattern === '' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('remove-cache-storage-item', cacheNamePattern, requestPattern); - const cacheStorage = self.caches; - if ( cacheStorage instanceof Object === false ) { return; } - const reCache = safe.patternToRegex(cacheNamePattern, undefined, true); - const reRequest = safe.patternToRegex(requestPattern, undefined, true); - cacheStorage.keys().then(cacheNames => { - for ( const cacheName of cacheNames ) { - if ( reCache.test(cacheName) === false ) { continue; } - if ( requestPattern === '' ) { - cacheStorage.delete(cacheName).then(result => { - if ( safe.logLevel > 1 ) { - safe.uboLog(logPrefix, `Deleting ${cacheName}`); - } - if ( result !== true ) { return; } - safe.uboLog(logPrefix, `Deleted ${cacheName}: ${result}`); - }); - continue; - } - cacheStorage.open(cacheName).then(cache => { - cache.keys().then(requests => { - for ( const request of requests ) { - if ( reRequest.test(request.url) === false ) { continue; } - if ( safe.logLevel > 1 ) { - safe.uboLog(logPrefix, `Deleting ${cacheName}/${request.url}`); - } - cache.delete(request).then(result => { - if ( result !== true ) { return; } - safe.uboLog(logPrefix, `Deleted ${cacheName}/${request.url}: ${result}`); - }); - } - }); - }); - } - }); -} /******************************************************************************* @@ -4169,150 +2962,6 @@ function replaceNodeText( replaceNodeTextFn(nodeName, pattern, replacement, ...extraArgs); } -/******************************************************************************* - * - * trusted-set-constant.js - * - * Set specified property to any value. This is essentially the same as - * set-constant.js, but with no restriction as to which values can be used. - * - **/ - -builtinScriptlets.push({ - name: 'trusted-set-constant.js', - requiresTrust: true, - aliases: [ - 'trusted-set.js', - ], - fn: trustedSetConstant, - dependencies: [ - 'set-constant.fn' - ], -}); -function trustedSetConstant( - ...args -) { - setConstantFn(true, ...args); -} - -/******************************************************************************* - * - * trusted-set-cookie.js - * - * Set specified cookie to an arbitrary value. - * - * Reference: - * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/trusted-set-cookie.js#L23 - * - **/ - -builtinScriptlets.push({ - name: 'trusted-set-cookie.js', - requiresTrust: true, - fn: trustedSetCookie, - world: 'ISOLATED', - dependencies: [ - 'safe-self.fn', - 'set-cookie.fn', - ], -}); -function trustedSetCookie( - name = '', - value = '', - offsetExpiresSec = '', - path = '' -) { - if ( name === '' ) { return; } - - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('set-cookie', name, value, path); - const time = new Date(); - - if ( value.includes('$now$') ) { - value = value.replaceAll('$now$', time.getTime()); - } - if ( value.includes('$currentDate$') ) { - value = value.replaceAll('$currentDate$', time.toUTCString()); - } - - let expires = ''; - if ( offsetExpiresSec !== '' ) { - if ( offsetExpiresSec === '1day' ) { - time.setDate(time.getDate() + 1); - } else if ( offsetExpiresSec === '1year' ) { - time.setFullYear(time.getFullYear() + 1); - } else { - if ( /^\d+$/.test(offsetExpiresSec) === false ) { return; } - time.setSeconds(time.getSeconds() + parseInt(offsetExpiresSec, 10)); - } - expires = time.toUTCString(); - } - - const done = setCookieFn( - true, - name, - value, - expires, - path, - safeSelf().getExtraArgs(Array.from(arguments), 4) - ); - - if ( done ) { - safe.uboLog(logPrefix, 'Done'); - } -} - -// For compatibility with AdGuard -builtinScriptlets.push({ - name: 'trusted-set-cookie-reload.js', - requiresTrust: true, - fn: trustedSetCookieReload, - world: 'ISOLATED', - dependencies: [ - 'trusted-set-cookie.js', - ], -}); -function trustedSetCookieReload(name, value, offsetExpiresSec, path, ...args) { - trustedSetCookie(name, value, offsetExpiresSec, path, 'reload', '1', ...args); -} - -/******************************************************************************* - * - * trusted-set-local-storage-item.js - * - * Set a local storage entry to an arbitrary value. - * - * Reference: - * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/trusted-set-local-storage-item.js - * - **/ - -builtinScriptlets.push({ - name: 'trusted-set-local-storage-item.js', - requiresTrust: true, - fn: trustedSetLocalStorageItem, - world: 'ISOLATED', - dependencies: [ - 'set-local-storage-item.fn', - ], -}); -function trustedSetLocalStorageItem(key = '', value = '') { - setLocalStorageItemFn('local', true, key, value); -} - -builtinScriptlets.push({ - name: 'trusted-set-session-storage-item.js', - requiresTrust: true, - fn: trustedSetSessionStorageItem, - world: 'ISOLATED', - dependencies: [ - 'set-local-storage-item.fn', - ], -}); -function trustedSetSessionStorageItem(key = '', value = '') { - setLocalStorageItemFn('session', true, key, value); -} - /******************************************************************************* * * trusted-replace-fetch-response.js @@ -4363,6 +3012,8 @@ function trustedReplaceXhrResponse( if ( pattern === '*' ) { pattern = '.*'; } const rePattern = safe.patternToRegex(pattern); const propNeedles = parsePropertiesToMatch(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 { open(method, url, ...args) { const outerXhr = this; @@ -4400,6 +3051,9 @@ function trustedReplaceXhrResponse( if ( typeof innerResponse !== 'string' ) { return (xhrDetails.response = innerResponse); } + if ( reIncludes && reIncludes.test(innerResponse) === false ) { + return (xhrDetails.response = innerResponse); + } const textBefore = innerResponse; const textAfter = textBefore.replace(rePattern, replacement); if ( textAfter !== textBefore ) { @@ -4447,7 +3101,7 @@ function trustedClickElement( const logPrefix = safe.makeLogPrefix('trusted-click-element', selectors, extraMatch, delay); if ( extraMatch !== '' ) { - const assertions = extraMatch.split(',').map(s => { + const assertions = safe.String_split.call(extraMatch, ',').map(s => { const pos1 = s.indexOf(':'); const s1 = pos1 !== -1 ? s.slice(0, pos1) : s; const not = s1.startsWith('!'); @@ -4515,7 +3169,7 @@ function trustedClickElement( return shadowRoot && querySelectorEx(inside, shadowRoot); }; - const selectorList = selectors.split(/\s*,\s*/) + const selectorList = safe.String_split.call(selectors, /\s*,\s*/) .filter(s => { try { void querySelectorEx(s); @@ -4642,10 +3296,10 @@ function trustedPruneInboundObject( const extraArgs = safe.getExtraArgs(Array.from(arguments), 4); const needlePaths = []; if ( rawPrunePaths !== '' ) { - needlePaths.push(...rawPrunePaths.split(/ +/)); + needlePaths.push(...safe.String_split.call(rawPrunePaths, / +/)); } if ( rawNeedlePaths !== '' ) { - needlePaths.push(...rawNeedlePaths.split(/ +/)); + needlePaths.push(...safe.String_split.call(rawNeedlePaths, / +/)); } const stackNeedle = safe.initPattern(extraArgs.stackToMatch || '', { canNegate: true }); const mustProcess = root => { @@ -4706,8 +3360,8 @@ function trustedPruneOutboundObject( if ( propChain === '' ) { return; } const safe = safeSelf(); const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); - const reflector = proxyApplyFn(propChain, function(...args) { - const objBefore = reflector(...args); + proxyApplyFn(propChain, function(context) { + const objBefore = context.reflect(); if ( objBefore instanceof Object === false ) { return objBefore; } const objAfter = objectPruneFn( objBefore, @@ -4722,44 +3376,6 @@ function trustedPruneOutboundObject( /******************************************************************************/ -builtinScriptlets.push({ - name: 'trusted-replace-argument.js', - requiresTrust: true, - fn: trustedReplaceArgument, - dependencies: [ - 'proxy-apply.fn', - 'safe-self.fn', - 'validate-constant.fn', - ], -}); -function trustedReplaceArgument( - propChain = '', - argpos = '', - argraw = '' -) { - if ( propChain === '' ) { return; } - if ( argpos === '' ) { return; } - if ( argraw === '' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('trusted-replace-argument', propChain, argpos, argraw); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); - const normalValue = validateConstantFn(true, argraw); - const reCondition = extraArgs.condition - ? safe.patternToRegex(extraArgs.condition) - : /^/; - const reflector = proxyApplyFn(propChain, function(...args) { - const arglist = args[args.length-1]; - if ( Array.isArray(arglist) === false ) { return reflector(...args); } - const argBefore = arglist[argpos]; - if ( reCondition.test(argBefore) === false ) { return reflector(...args); } - arglist[argpos] = normalValue; - safe.uboLog(logPrefix, `Replaced argument:\nBefore: ${JSON.stringify(argBefore)}\nAfter: ${normalValue}`); - return reflector(...args); - }); -} - -/******************************************************************************/ - builtinScriptlets.push({ name: 'trusted-replace-outbound-text.js', requiresTrust: true, @@ -4771,24 +3387,27 @@ builtinScriptlets.push({ }); function trustedReplaceOutboundText( propChain = '', - pattern = '', - replacement = '', + rawPattern = '', + rawReplacement = '', ...args ) { if ( propChain === '' ) { return; } const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('trusted-replace-outbound-text', propChain, pattern, replacement, ...args); - const rePattern = safe.patternToRegex(pattern); + const logPrefix = safe.makeLogPrefix('trusted-replace-outbound-text', propChain, rawPattern, rawReplacement, ...args); + const rePattern = safe.patternToRegex(rawPattern); + const replacement = rawReplacement.startsWith('json:') + ? safe.JSON_parse(rawReplacement.slice(5)) + : rawReplacement; const extraArgs = safe.getExtraArgs(args); const reCondition = safe.patternToRegex(extraArgs.condition || ''); - const reflector = proxyApplyFn(propChain, function(...args) { - const encodedTextBefore = reflector(...args); + proxyApplyFn(propChain, function(context) { + const encodedTextBefore = context.reflect(); let textBefore = encodedTextBefore; if ( extraArgs.encoding === 'base64' ) { try { textBefore = self.atob(encodedTextBefore); } catch(ex) { return encodedTextBefore; } } - if ( pattern === '' ) { + if ( rawPattern === '' ) { safe.uboLog(logPrefix, 'Decoded outbound text:\n', textBefore); return encodedTextBefore; } @@ -4808,4 +3427,253 @@ function trustedReplaceOutboundText( }); } +/******************************************************************************* + * + * Reference: + * https://github.com/AdguardTeam/Scriptlets/blob/5a92d79489/wiki/about-trusted-scriptlets.md#trusted-suppress-native-method + * + * This is a first version with current limitations: + * - Does not support matching arguments which are object or array + * - Does not support `stack` parameter + * + * If `signatureStr` parameter is not declared, the scriptlet will log all calls + * to `methodPath` along with the arguments passed and will not prevent the + * trapped method. + * + * */ + +builtinScriptlets.push({ + name: 'trusted-suppress-native-method.js', + requiresTrust: true, + fn: trustedSuppressNativeMethod, + dependencies: [ + 'matches-stack-trace.fn', + 'proxy-apply.fn', + 'safe-self.fn', + ], +}); +function trustedSuppressNativeMethod( + methodPath = '', + signature = '', + how = '', + stack = '' +) { + if ( methodPath === '' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('trusted-suppress-native-method', methodPath, signature, how, stack); + const signatureArgs = safe.String_split.call(signature, /\s*\|\s*/).map(v => { + if ( /^".*"$/.test(v) ) { + return { type: 'pattern', re: safe.patternToRegex(v.slice(1, -1)) }; + } + if ( v === 'false' ) { + return { type: 'exact', value: false }; + } + if ( v === 'true' ) { + return { type: 'exact', value: true }; + } + if ( v === 'null' ) { + return { type: 'exact', value: null }; + } + if ( v === 'undefined' ) { + return { type: 'exact', value: undefined }; + } + }); + const stackNeedle = safe.initPattern(stack, { canNegate: true }); + proxyApplyFn(methodPath, function(context) { + const { callArgs } = context; + if ( signature === '' ) { + safe.uboLog(logPrefix, `Arguments:\n${callArgs.join('\n')}`); + return context.reflect(); + } + for ( let i = 0; i < signatureArgs.length; i++ ) { + const signatureArg = signatureArgs[i]; + if ( signatureArg === undefined ) { continue; } + const targetArg = i < callArgs.length ? callArgs[i] : undefined; + if ( signatureArg.type === 'exact' ) { + if ( targetArg !== signatureArg.value ) { + return context.reflect(); + } + } + if ( signatureArg.type === 'pattern' ) { + if ( safe.RegExp_test.call(signatureArg.re, targetArg) === false ) { + return context.reflect(); + } + } + } + if ( stackNeedle.matchAll !== true ) { + const logLevel = safe.logLevel > 1 ? 'all' : ''; + if ( matchesStackTraceFn(stackNeedle, logLevel) === false ) { + return context.reflect(); + } + } + if ( how === 'debug' ) { + debugger; // eslint-disable-line no-debugger + return context.reflect(); + } + safe.uboLog(logPrefix, `Suppressed:\n${callArgs.join('\n')}`); + if ( how === 'abort' ) { + throw new ReferenceError(); + } + }); +} + +/******************************************************************************* + * + * Trusted version of prevent-xhr(), which allows the use of an arbitrary + * string as response text. + * + * */ + +builtinScriptlets.push({ + name: 'trusted-prevent-xhr.js', + requiresTrust: true, + fn: trustedPreventXhr, + dependencies: [ + 'prevent-xhr.fn', + ], +}); +function trustedPreventXhr(...args) { + return preventXhrFn(true, ...args); +} + +/** + * @trustedScriptlet trusted-prevent-dom-bypass + * + * @description + * Prevent the bypassing of uBO scriptlets through anonymous embedded context. + * + * Ensure that a target method in the embedded context is using the + * corresponding parent context's method (which is assumed to be + * properly patched), or to replace the embedded context with that of the + * parent context. + * + * Root issue: + * https://issues.chromium.org/issues/40202434 + * + * @param methodPath + * The method which calls must be intercepted. The arguments + * of the intercepted calls are assumed to be HTMLElement, anything else will + * be ignored. + * + * @param [targetProp] + * The method in the embedded context which should be delegated to the + * parent context. If no method is specified, the embedded context becomes + * the parent one, i.e. all properties of the embedded context will be that + * of the parent context. + * + * @example + * ##+js(trusted-prevent-dom-bypass, Element.prototype.append, open) + * + * @example + * ##+js(trusted-prevent-dom-bypass, Element.prototype.appendChild, XMLHttpRequest) + * + * */ + +builtinScriptlets.push({ + name: 'trusted-prevent-dom-bypass.js', + requiresTrust: true, + fn: trustedPreventDomBypass, + dependencies: [ + 'proxy-apply.fn', + 'safe-self.fn', + ], +}); +function trustedPreventDomBypass( + methodPath = '', + targetProp = '' +) { + if ( methodPath === '' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('trusted-prevent-dom-bypass', methodPath, targetProp); + proxyApplyFn(methodPath, function(context) { + const elems = new Set(context.callArgs.filter(e => e instanceof HTMLElement)); + const r = context.reflect(); + if ( elems.length === 0 ) { return r; } + for ( const elem of elems ) { + try { + if ( `${elem.contentWindow}` !== '[object Window]' ) { continue; } + if ( elem.contentWindow.location.href !== 'about:blank' ) { + if ( elem.contentWindow.location.href !== self.location.href ) { + continue; + } + } + if ( targetProp !== '' ) { + elem.contentWindow[targetProp] = self[targetProp]; + } else { + Object.defineProperty(elem, 'contentWindow', { value: self }); + } + safe.uboLog(logPrefix, 'Bypass prevented'); + } catch(_) { + } + } + return r; + }); +} + +/** + * @trustedScriptlet trusted-override-element-method + * + * @description + * Override the behavior of a method on matching elements. + * + * @param methodPath + * The method which calls must be intercepted. + * + * @param [selector] + * A CSS selector which the target element must match. If not specified, + * the override will occur for all elements. + * + * @param [disposition] + * How the override should be handled. If not specified, the overridden call + * will be equivalent to an empty function. If set to `throw`, an exception + * will be thrown. Any other value will be validated and returned as a + * supported safe constant. + * + * @example + * ##+js(trusted-override-element-method, HTMLAnchorElement.prototype.click, a[target="_blank"][style]) + * + * */ + +builtinScriptlets.push({ + name: 'trusted-override-element-method.js', + requiresTrust: true, + fn: trustedOverrideElementMethod, + dependencies: [ + 'proxy-apply.fn', + 'safe-self.fn', + 'validate-constant.fn', + ], +}); +function trustedOverrideElementMethod( + methodPath = '', + selector = '', + disposition = '' +) { + if ( methodPath === '' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('trusted-override-element-method', methodPath, selector, disposition); + proxyApplyFn(methodPath, function(context) { + let override = selector === ''; + if ( override === false ) { + const { thisArg } = context; + try { + override = thisArg.closest(selector) === thisArg; + } catch(_) { + } + } + if ( override === false ) { + return context.reflect(); + } + safe.uboLog(logPrefix, 'Overridden'); + if ( disposition === '' ) { return; } + if ( disposition === 'debug' && safe.logLevel !== 0 ) { + debugger; // eslint-disable-line no-debugger + } + if ( disposition === 'throw' ) { + throw new ReferenceError(); + } + return validateConstantFn(false, disposition); + }); +} + /******************************************************************************/ diff --git a/src/js/resources/set-constant.js b/src/js/resources/set-constant.js new file mode 100644 index 0000000000000..127f27bbbe910 --- /dev/null +++ b/src/js/resources/set-constant.js @@ -0,0 +1,287 @@ +/******************************************************************************* + + 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 { runAt } from './run-at.js'; +import { safeSelf } from './safe-self.js'; + +/******************************************************************************/ + +export function validateConstantFn(trusted, raw, extraArgs = {}) { + const safe = safeSelf(); + let value; + if ( raw === 'undefined' ) { + value = undefined; + } else if ( raw === 'false' ) { + value = false; + } else if ( raw === 'true' ) { + value = true; + } else if ( raw === 'null' ) { + value = null; + } else if ( raw === "''" || raw === '' ) { + value = ''; + } else if ( raw === '[]' || raw === 'emptyArr' ) { + value = []; + } else if ( raw === '{}' || raw === 'emptyObj' ) { + value = {}; + } else if ( raw === 'noopFunc' ) { + value = function(){}; + } else if ( raw === 'trueFunc' ) { + value = function(){ return true; }; + } else if ( raw === 'falseFunc' ) { + value = function(){ return false; }; + } else if ( raw === 'throwFunc' ) { + value = function(){ throw ''; }; + } else if ( /^-?\d+$/.test(raw) ) { + value = parseInt(raw); + if ( isNaN(raw) ) { return; } + if ( Math.abs(raw) > 0x7FFF ) { return; } + } else if ( trusted ) { + if ( raw.startsWith('json:') ) { + try { value = safe.JSON_parse(raw.slice(5)); } catch(ex) { return; } + } else if ( raw.startsWith('{') && raw.endsWith('}') ) { + try { value = safe.JSON_parse(raw).value; } catch(ex) { return; } + } + } else { + return; + } + if ( extraArgs.as !== undefined ) { + if ( extraArgs.as === 'function' ) { + return ( ) => value; + } else if ( extraArgs.as === 'callback' ) { + return ( ) => (( ) => value); + } else if ( extraArgs.as === 'resolved' ) { + return Promise.resolve(value); + } else if ( extraArgs.as === 'rejected' ) { + return Promise.reject(value); + } + } + return value; +} +registerScriptlet(validateConstantFn, { + name: 'validate-constant.fn', + dependencies: [ + safeSelf, + ], +}); + +/******************************************************************************/ + +export function setConstantFn( + trusted = false, + chain = '', + rawValue = '' +) { + if ( chain === '' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('set-constant', chain, rawValue); + const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); + function setConstant(chain, rawValue) { + const trappedProp = (( ) => { + const pos = chain.lastIndexOf('.'); + if ( pos === -1 ) { return chain; } + return chain.slice(pos+1); + })(); + const cloakFunc = fn => { + safe.Object_defineProperty(fn, 'name', { value: trappedProp }); + return new Proxy(fn, { + defineProperty(target, prop) { + if ( prop !== 'toString' ) { + return Reflect.defineProperty(...arguments); + } + return true; + }, + deleteProperty(target, prop) { + if ( prop !== 'toString' ) { + return Reflect.deleteProperty(...arguments); + } + return true; + }, + get(target, prop) { + if ( prop === 'toString' ) { + return function() { + return `function ${trappedProp}() { [native code] }`; + }.bind(null); + } + return Reflect.get(...arguments); + }, + }); + }; + if ( trappedProp === '' ) { return; } + const thisScript = document.currentScript; + let normalValue = validateConstantFn(trusted, rawValue, extraArgs); + if ( rawValue === 'noopFunc' || rawValue === 'trueFunc' || rawValue === 'falseFunc' ) { + normalValue = cloakFunc(normalValue); + } + let aborted = false; + const mustAbort = function(v) { + if ( trusted ) { return false; } + if ( aborted ) { return true; } + aborted = + (v !== undefined && v !== null) && + (normalValue !== undefined && normalValue !== null) && + (typeof v !== typeof normalValue); + if ( aborted ) { + safe.uboLog(logPrefix, `Aborted because value set to ${v}`); + } + return aborted; + }; + // https://github.com/uBlockOrigin/uBlock-issues/issues/156 + // Support multiple trappers for the same property. + const trapProp = function(owner, prop, configurable, handler) { + if ( handler.init(configurable ? owner[prop] : normalValue) === false ) { return; } + const odesc = safe.Object_getOwnPropertyDescriptor(owner, prop); + let prevGetter, prevSetter; + if ( odesc instanceof safe.Object ) { + owner[prop] = normalValue; + if ( odesc.get instanceof Function ) { + prevGetter = odesc.get; + } + if ( odesc.set instanceof Function ) { + prevSetter = odesc.set; + } + } + try { + safe.Object_defineProperty(owner, prop, { + configurable, + get() { + if ( prevGetter !== undefined ) { + prevGetter(); + } + return handler.getter(); + }, + set(a) { + if ( prevSetter !== undefined ) { + prevSetter(a); + } + handler.setter(a); + } + }); + safe.uboLog(logPrefix, 'Trap installed'); + } catch(ex) { + safe.uboErr(logPrefix, ex); + } + }; + const trapChain = function(owner, chain) { + const pos = chain.indexOf('.'); + if ( pos === -1 ) { + trapProp(owner, chain, false, { + v: undefined, + init: function(v) { + if ( mustAbort(v) ) { return false; } + this.v = v; + return true; + }, + getter: function() { + if ( document.currentScript === thisScript ) { + return this.v; + } + safe.uboLog(logPrefix, 'Property read'); + return normalValue; + }, + setter: function(a) { + if ( mustAbort(a) === false ) { return; } + normalValue = a; + } + }); + return; + } + const prop = chain.slice(0, pos); + const v = owner[prop]; + chain = chain.slice(pos + 1); + if ( v instanceof safe.Object || typeof v === 'object' && v !== null ) { + trapChain(v, chain); + return; + } + trapProp(owner, prop, true, { + v: undefined, + init: function(v) { + this.v = v; + return true; + }, + getter: function() { + return this.v; + }, + setter: function(a) { + this.v = a; + if ( a instanceof safe.Object ) { + trapChain(a, chain); + } + } + }); + }; + trapChain(window, chain); + } + runAt(( ) => { + setConstant(chain, rawValue); + }, extraArgs.runAt); +} +registerScriptlet(setConstantFn, { + name: 'set-constant.fn', + dependencies: [ + runAt, + safeSelf, + validateConstantFn, + ], +}); + +/******************************************************************************/ + +export function setConstant( + ...args +) { + setConstantFn(false, ...args); +} +registerScriptlet(setConstant, { + name: 'set-constant.js', + aliases: [ + 'set.js', + ], + dependencies: [ + setConstantFn, + ], +}); + +/******************************************************************************* + * + * trusted-set-constant.js + * + * Set specified property to any value. This is essentially the same as + * set-constant.js, but with no restriction as to which values can be used. + * + **/ + +export function trustedSetConstant( + ...args +) { + setConstantFn(true, ...args); +} +registerScriptlet(trustedSetConstant, { + name: 'trusted-set-constant.js', + requiresTrust: true, + aliases: [ + 'trusted-set.js', + ], + dependencies: [ + setConstantFn, + ], +}); diff --git a/src/js/resources/shared.js b/src/js/resources/shared.js new file mode 100644 index 0000000000000..9a38fca48105b --- /dev/null +++ b/src/js/resources/shared.js @@ -0,0 +1,44 @@ +/******************************************************************************* + + 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 + +*/ + +// Code imported from main code base and exposed as injectable scriptlets +import { ArglistParser } from '../arglist-parser.js'; + +import { registerScriptlet } from './base.js'; + +/******************************************************************************/ + +registerScriptlet(ArglistParser, { + name: 'arglist-parser.fn', +}); + +/******************************************************************************/ + +export function createArglistParser(...args) { + return new ArglistParser(...args); +} +registerScriptlet(createArglistParser, { + name: 'create-arglist-parser.fn', + dependencies: [ + ArglistParser, + ], +}); diff --git a/src/js/resources/spoof-css.js b/src/js/resources/spoof-css.js new file mode 100644 index 0000000000000..7cc7b9f95574c --- /dev/null +++ b/src/js/resources/spoof-css.js @@ -0,0 +1,163 @@ +/******************************************************************************* + + 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'; + +/** + * @scriptlet spoof-css.js + * + * @description + * Spoof the value of CSS properties. + * + * @param selector + * A CSS selector for the element(s) to target. + * + * @param [property, value, ...] + * A list of property-value pairs of the style properties to spoof to the + * specified values. +* + * */ + +export function spoofCSS( + selector, + ...args +) { + if ( typeof selector !== 'string' ) { return; } + if ( selector === '' ) { return; } + const toCamelCase = s => s.replace(/-[a-z]/g, s => s.charAt(1).toUpperCase()); + const propToValueMap = new Map(); + const privatePropToValueMap = new Map(); + for ( let i = 0; i < args.length; i += 2 ) { + const prop = toCamelCase(args[i+0]); + if ( prop === '' ) { break; } + const value = args[i+1]; + if ( typeof value !== 'string' ) { break; } + if ( prop.charCodeAt(0) === 0x5F /* _ */ ) { + privatePropToValueMap.set(prop, value); + } else { + propToValueMap.set(prop, value); + } + } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('spoof-css', selector, ...args); + const instanceProperties = [ 'cssText', 'length', 'parentRule' ]; + const spoofStyle = (prop, real) => { + const normalProp = toCamelCase(prop); + const shouldSpoof = propToValueMap.has(normalProp); + const value = shouldSpoof ? propToValueMap.get(normalProp) : real; + if ( shouldSpoof ) { + safe.uboLog(logPrefix, `Spoofing ${prop} to ${value}`); + } + return value; + }; + const cloackFunc = (fn, thisArg, name) => { + const trap = fn.bind(thisArg); + Object.defineProperty(trap, 'name', { value: name }); + Object.defineProperty(trap, 'toString', { + value: ( ) => `function ${name}() { [native code] }` + }); + return trap; + }; + self.getComputedStyle = new Proxy(self.getComputedStyle, { + apply: function(target, thisArg, args) { + // eslint-disable-next-line no-debugger + if ( privatePropToValueMap.has('_debug') ) { debugger; } + const style = Reflect.apply(target, thisArg, args); + const targetElements = new WeakSet(document.querySelectorAll(selector)); + if ( targetElements.has(args[0]) === false ) { return style; } + const proxiedStyle = new Proxy(style, { + get(target, prop) { + if ( typeof target[prop] === 'function' ) { + if ( prop === 'getPropertyValue' ) { + return cloackFunc(function getPropertyValue(prop) { + return spoofStyle(prop, target[prop]); + }, target, 'getPropertyValue'); + } + return cloackFunc(target[prop], target, prop); + } + if ( instanceProperties.includes(prop) ) { + return Reflect.get(target, prop); + } + return spoofStyle(prop, Reflect.get(target, prop)); + }, + getOwnPropertyDescriptor(target, prop) { + if ( propToValueMap.has(prop) ) { + return { + configurable: true, + enumerable: true, + value: propToValueMap.get(prop), + writable: true, + }; + } + return Reflect.getOwnPropertyDescriptor(target, prop); + }, + }); + return proxiedStyle; + }, + get(target, prop) { + if ( prop === 'toString' ) { + return target.toString.bind(target); + } + return Reflect.get(target, prop); + }, + }); + Element.prototype.getBoundingClientRect = new Proxy(Element.prototype.getBoundingClientRect, { + apply: function(target, thisArg, args) { + // eslint-disable-next-line no-debugger + if ( privatePropToValueMap.has('_debug') ) { debugger; } + const rect = Reflect.apply(target, thisArg, args); + const targetElements = new WeakSet(document.querySelectorAll(selector)); + if ( targetElements.has(thisArg) === false ) { return rect; } + let { x, y, height, width } = rect; + if ( privatePropToValueMap.has('_rectx') ) { + x = parseFloat(privatePropToValueMap.get('_rectx')); + } + if ( privatePropToValueMap.has('_recty') ) { + y = parseFloat(privatePropToValueMap.get('_recty')); + } + if ( privatePropToValueMap.has('_rectw') ) { + width = parseFloat(privatePropToValueMap.get('_rectw')); + } else if ( propToValueMap.has('width') ) { + width = parseFloat(propToValueMap.get('width')); + } + if ( privatePropToValueMap.has('_recth') ) { + height = parseFloat(privatePropToValueMap.get('_recth')); + } else if ( propToValueMap.has('height') ) { + height = parseFloat(propToValueMap.get('height')); + } + return new self.DOMRect(x, y, width, height); + }, + get(target, prop) { + if ( prop === 'toString' ) { + return target.toString.bind(target); + } + return Reflect.get(target, prop); + }, + }); +} +registerScriptlet(spoofCSS, { + name: 'spoof-css.js', + dependencies: [ + safeSelf, + ], +}); diff --git a/src/js/s14e-serializer.js b/src/js/s14e-serializer.js index 0c9200ebcaa14..8b1850f136fe9 100644 --- a/src/js/s14e-serializer.js +++ b/src/js/s14e-serializer.js @@ -249,8 +249,29 @@ const toArrayBufferViewConstructor = { /******************************************************************************/ -const textDecoder = new TextDecoder(); -const textEncoder = new TextEncoder(); +const textCodec = { + decoder: null, + encoder: null, + decode(...args) { + if ( this.decoder === null ) { + this.decoder = new globalThis.TextDecoder(); + } + return this.decoder.decode(...args); + }, + encode(...args) { + if ( this.encoder === null ) { + this.encoder = new globalThis.TextEncoder(); + } + return this.encoder.encode(...args); + }, + encodeInto(...args) { + if ( this.encoder === null ) { + this.encoder = new globalThis.TextEncoder(); + } + return this.encoder.encodeInto(...args); + }, +}; + const isInteger = Number.isInteger; const writeRefs = new Map(); @@ -269,7 +290,7 @@ const uint8InputFromAsciiStr = s => { if ( uint8Input === null || uint8Input.length < s.length ) { uint8Input = new Uint8Array(s.length + 0x03FF & ~0x03FF); } - textEncoder.encodeInto(s, uint8Input); + textCodec.encodeInto(s, uint8Input); return uint8Input; }; @@ -407,7 +428,7 @@ const denseArrayBufferToStr = (arrbuf, details) => { } } } - return textDecoder.decode(output); + return textCodec.decode(output); }; const BASE88_POW1 = NUMSAFECHARS; @@ -489,7 +510,7 @@ const sparseArrayBufferToStr = (arrbuf, details) => { uint8out[j++] = SEPARATORCHARCODE; } } - return textDecoder.decode(uint8out); + return textCodec.decode(uint8out); }; const sparseArrayBufferFromStr = (sparseStr, arrbuf) => { @@ -592,7 +613,8 @@ const _serialize = data => { return; } if ( xtypeInt === I_DATE ) { - writeBuffer.push(C_DATE + _serialize(data.getTime())); + writeBuffer.push(C_DATE); + _serialize(data.getTime()); return; } // Reference to composite types @@ -1059,7 +1081,7 @@ export const serialize = (data, options = {}) => { writeBuffer.length = 0; if ( shouldCompress(s, options) === false ) { return s; } const lz4Util = new LZ4BlockJS(); - const uint8ArrayBefore = textEncoder.encode(s); + const uint8ArrayBefore = textCodec.encode(s); const uint8ArrayAfter = lz4Util.encode(uint8ArrayBefore, 0); const lz4 = { size: uint8ArrayBefore.length, @@ -1075,32 +1097,36 @@ export const serialize = (data, options = {}) => { return ratio <= 0.85 ? t : s; }; -export const deserialize = s => { - if ( s.startsWith(MAGICLZ4PREFIX) ) { - refCounter = 1; - readStr = s; - readEnd = s.length; - readPtr = MAGICLZ4PREFIX.length; - const lz4 = _deserialize(); - readRefs.clear(); - readStr = ''; - const lz4Util = new LZ4BlockJS(); - const uint8ArrayAfter = lz4Util.decode(lz4.data, 0, lz4.size); - s = textDecoder.decode(new Uint8Array(uint8ArrayAfter)); - } - if ( s.startsWith(MAGICPREFIX) === false ) { return; } +const deserializeById = (blockid, s) => { refCounter = 1; readStr = s; readEnd = s.length; - readPtr = MAGICPREFIX.length; + readPtr = blockid.length; const data = _deserialize(); readRefs.clear(); readStr = ''; - uint8Input = null; if ( readPtr === FAILMARK ) { return; } return data; }; +export const deserialize = s => { + if ( s.startsWith(MAGICLZ4PREFIX) ) { + const lz4 = deserializeById(MAGICLZ4PREFIX, s); + if ( lz4 ) { + const lz4Util = new LZ4BlockJS(); + const uint8ArrayAfter = lz4Util.decode(lz4.data, 0, lz4.size); + if ( uint8ArrayAfter ) { + s = textCodec.decode(new Uint8Array(uint8ArrayAfter)); + } + } + } + const data = s.startsWith(MAGICPREFIX) + ? deserializeById(MAGICPREFIX, s) + : undefined; + uint8Input = null; + return data; +}; + export const isSerialized = s => typeof s === 'string' && (s.startsWith(MAGICLZ4PREFIX) || s.startsWith(MAGICPREFIX)); diff --git a/src/js/scriptlet-filtering-core.js b/src/js/scriptlet-filtering-core.js index 907844fbc198a..0fec05c2ba7a2 100644 --- a/src/js/scriptlet-filtering-core.js +++ b/src/js/scriptlet-filtering-core.js @@ -99,7 +99,7 @@ const patchScriptlet = (content, arglist) => { }; const requote = s => { - if ( /^(["'`]).+\1$|,/.test(s) === false ) { return s; } + if ( /^(["'`]).*\1$|,|^$/.test(s) === false ) { return s; } if ( s.includes("'") === false ) { return `'${s}'`; } if ( s.includes('"') === false ) { return `"${s}"`; } if ( s.includes('`') === false ) { return `\`${s}\``; } diff --git a/src/js/scriptlet-filtering.js b/src/js/scriptlet-filtering.js index 98f2a64a39a5d..b7a0617722838 100644 --- a/src/js/scriptlet-filtering.js +++ b/src/js/scriptlet-filtering.js @@ -61,6 +61,7 @@ const contentScriptRegisterer = new (class { runAt: 'document_start', }).then(handle => { this.hostnameToDetails.set(hostname, { handle, code }); + return handle; }).catch(( ) => { this.hostnameToDetails.delete(hostname); }); @@ -94,7 +95,9 @@ const contentScriptRegisterer = new (class { } unregisterHandle(handle) { if ( handle instanceof Promise ) { - handle.then(handle => { handle.unregister(); }); + handle.then(handle => { + if ( handle ) { handle.unregister(); } + }); } else { handle.unregister(); } @@ -103,36 +106,6 @@ const contentScriptRegisterer = new (class { /******************************************************************************/ -const mainWorldInjector = (( ) => { - const parts = [ - '(', - function(injector, details) { - if ( typeof self.uBO_scriptletsInjected === 'string' ) { return; } - const doc = document; - if ( doc.location === null ) { return; } - const hostname = doc.location.hostname; - if ( hostname !== '' && details.hostname !== hostname ) { return; } - injector(doc, details); - return 0; - }.toString(), - ')(', - vAPI.scriptletsInjector, ', ', - 'json-slot', - ');', - ]; - const jsonSlot = parts.indexOf('json-slot'); - return { - assemble: function(hostname, details) { - parts[jsonSlot] = JSON.stringify({ - hostname, - scriptlets: details.mainWorld, - filters: details.filters, - }); - return parts.join(''); - }, - }; -})(); - const isolatedWorldInjector = (( ) => { const parts = [ '(', @@ -173,25 +146,28 @@ const onScriptletMessageInjector = (( ) => { '(', function(name) { if ( self.uBO_bcSecret ) { return; } - const bcSecret = new self.BroadcastChannel(name); - bcSecret.onmessage = ev => { - const msg = ev.data; - switch ( typeof msg ) { - case 'string': - if ( msg !== 'areyouready?' ) { break; } - bcSecret.postMessage('iamready!'); - break; - case 'object': - if ( self.vAPI && self.vAPI.messaging ) { - self.vAPI.messaging.send('contentscript', msg); - } else { - console.log(`[uBO][${msg.type}]${msg.text}`); + try { + const bcSecret = new self.BroadcastChannel(name); + bcSecret.onmessage = ev => { + const msg = ev.data; + switch ( typeof msg ) { + case 'string': + if ( msg !== 'areyouready?' ) { break; } + bcSecret.postMessage('iamready!'); + break; + case 'object': + if ( self.vAPI && self.vAPI.messaging ) { + self.vAPI.messaging.send('contentscript', msg); + } else { + console.log(`[uBO][${msg.type}]${msg.text}`); + } + break; } - break; - } - }; - bcSecret.postMessage('iamready!'); - self.uBO_bcSecret = bcSecret; + }; + bcSecret.postMessage('iamready!'); + self.uBO_bcSecret = bcSecret; + } catch(_) { + } }.toString(), ')(', 'bcSecret-slot', @@ -328,7 +304,7 @@ export class ScriptletFilteringEngineEx extends ScriptletFilteringEngine { const contentScript = []; if ( scriptletDetails.mainWorld ) { - contentScript.push(mainWorldInjector.assemble(hostname, scriptletDetails)); + contentScript.push(vAPI.scriptletsInjector(hostname, scriptletDetails)); } if ( scriptletDetails.isolatedWorld ) { contentScript.push(isolatedWorldInjector.assemble(hostname, scriptletDetails)); diff --git a/src/js/scriptlets/load-large-media-interactive.js b/src/js/scriptlets/load-large-media-interactive.js index 57198e4b2dfec..6158124726c70 100644 --- a/src/js/scriptlets/load-large-media-interactive.js +++ b/src/js/scriptlets/load-large-media-interactive.js @@ -19,10 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - (( ) => { /******************************************************************************/ @@ -32,8 +28,6 @@ if ( typeof vAPI !== 'object' || vAPI.loadAllLargeMedia instanceof Function ) { return; } -/******************************************************************************/ - const largeMediaElementAttribute = 'data-' + vAPI.sessionId; const largeMediaElementSelector = ':root audio[' + largeMediaElementAttribute + '],\n' + @@ -41,25 +35,19 @@ const largeMediaElementSelector = ':root picture[' + largeMediaElementAttribute + '],\n' + ':root video[' + largeMediaElementAttribute + ']'; -/******************************************************************************/ +const isMediaElement = elem => + (/^(?:audio|img|picture|video)$/.test(elem.localName)); -const isMediaElement = function(elem) { - return /^(?:audio|img|picture|video)$/.test(elem.localName); -}; +const isPlayableMediaElement = elem => + (/^(?:audio|video)$/.test(elem.localName)); /******************************************************************************/ const mediaNotLoaded = function(elem) { switch ( elem.localName ) { case 'audio': - case 'video': { - const src = elem.src || ''; - if ( src.startsWith('blob:') ) { - elem.autoplay = false; - elem.pause(); - } + case 'video': return elem.readyState === 0 || elem.error !== null; - } case 'img': { if ( elem.naturalWidth !== 0 || elem.naturalHeight !== 0 ) { break; @@ -103,44 +91,41 @@ const surveyMissingMediaElements = function() { return largeMediaElementCount; }; -if ( surveyMissingMediaElements() === 0 ) { return; } - -// Insert CSS to highlight blocked media elements. -if ( vAPI.largeMediaElementStyleSheet === undefined ) { - vAPI.largeMediaElementStyleSheet = [ - largeMediaElementSelector + ' {', - 'border: 2px dotted red !important;', - 'box-sizing: border-box !important;', - 'cursor: zoom-in !important;', - 'display: inline-block;', - 'filter: none !important;', - 'font-size: 1rem !important;', - 'min-height: 1em !important;', - 'min-width: 1em !important;', - 'opacity: 1 !important;', - 'outline: none !important;', - 'transform: none !important;', - 'visibility: visible !important;', - 'z-index: 2147483647', - '}', - ].join('\n'); - vAPI.userStylesheet.add(vAPI.largeMediaElementStyleSheet); - vAPI.userStylesheet.apply(); +if ( surveyMissingMediaElements() ) { + // Insert CSS to highlight blocked media elements. + if ( vAPI.largeMediaElementStyleSheet === undefined ) { + vAPI.largeMediaElementStyleSheet = [ + largeMediaElementSelector + ' {', + 'border: 2px dotted red !important;', + 'box-sizing: border-box !important;', + 'cursor: zoom-in !important;', + 'display: inline-block;', + 'filter: none !important;', + 'font-size: 1rem !important;', + 'min-height: 1em !important;', + 'min-width: 1em !important;', + 'opacity: 1 !important;', + 'outline: none !important;', + 'transform: none !important;', + 'visibility: visible !important;', + 'z-index: 2147483647', + '}', + ].join('\n'); + vAPI.userStylesheet.add(vAPI.largeMediaElementStyleSheet); + vAPI.userStylesheet.apply(); + } } /******************************************************************************/ const loadMedia = async function(elem) { const src = elem.getAttribute('src') || ''; + if ( src === '' ) { return; } elem.removeAttribute('src'); - await vAPI.messaging.send('scriptlets', { what: 'temporarilyAllowLargeMediaElement', }); - - if ( src !== '' ) { - elem.setAttribute('src', src); - } + elem.setAttribute('src', src); elem.load(); }; @@ -148,14 +133,21 @@ const loadMedia = async function(elem) { const loadImage = async function(elem) { const src = elem.getAttribute('src') || ''; - elem.removeAttribute('src'); - + const srcset = src === '' && elem.getAttribute('srcset') || ''; + if ( src === '' && srcset === '' ) { return; } + if ( src !== '' ) { + elem.removeAttribute('src'); + } + if ( srcset !== '' ) { + elem.removeAttribute('srcset'); + } await vAPI.messaging.send('scriptlets', { what: 'temporarilyAllowLargeMediaElement', }); - if ( src !== '' ) { elem.setAttribute('src', src); + } else if ( srcset !== '' ) { + elem.setAttribute('srcset', srcset); } }; @@ -258,6 +250,27 @@ document.addEventListener('error', onLoadError, true); /******************************************************************************/ +const autoPausedMedia = new WeakMap(); + +for ( const elem of document.querySelectorAll('audio,video') ) { + elem.setAttribute('autoplay', 'false'); +} + +const preventAutoplay = function(ev) { + const elem = ev.target; + if ( isPlayableMediaElement(elem) === false ) { return; } + const currentSrc = elem.getAttribute('src') || ''; + const pausedSrc = autoPausedMedia.get(elem); + if ( pausedSrc === currentSrc ) { return; } + autoPausedMedia.set(elem, currentSrc); + elem.setAttribute('autoplay', 'false'); + elem.pause(); +}; + +document.addEventListener('timeupdate', preventAutoplay, true); + +/******************************************************************************/ + vAPI.loadAllLargeMedia = function() { document.removeEventListener('click', onMouseClick, true); document.removeEventListener('loadeddata', onLoadedData, true); diff --git a/src/js/scriptlets/should-inject-contentscript.js b/src/js/scriptlets/should-inject-contentscript.js index 94d0cd3f1e571..2317e20688777 100644 --- a/src/js/scriptlets/should-inject-contentscript.js +++ b/src/js/scriptlets/should-inject-contentscript.js @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - // If content scripts are already injected, we need to respond with `false`, // to "should inject content scripts?" // @@ -31,7 +29,7 @@ try { const status = vAPI.uBO !== true; if ( status === false && vAPI.bootstrap ) { - self.requestIdleCallback(( ) => vAPI && vAPI.bootstrap()); + self.requestIdleCallback(( ) => vAPI?.bootstrap?.()); } return status; } catch(ex) { diff --git a/src/js/static-dnr-filtering.js b/src/js/static-dnr-filtering.js index ca66b861df619..9935fd161e45c 100644 --- a/src/js/static-dnr-filtering.js +++ b/src/js/static-dnr-filtering.js @@ -19,12 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - -import staticNetFilteringEngine from './static-net-filtering.js'; -import { LineIterator } from './text-utils.js'; import * as sfp from './static-filtering-parser.js'; import { @@ -32,6 +26,9 @@ import { CompiledListWriter, } from './static-filtering-io.js'; +import { LineIterator } from './text-utils.js'; +import staticNetFilteringEngine from './static-net-filtering.js'; + /******************************************************************************/ // http://www.cse.yorku.ca/~oz/hash.html#djb2 @@ -47,13 +44,15 @@ const hashFromStr = (type, s) => { return hash & 0xFFFFFF; }; +const isRegex = hn => hn.startsWith('/') && hn.endsWith('/'); + /******************************************************************************/ // Copied from cosmetic-filter.js for the time being to avoid unwanted // dependencies const rePlainSelector = /^[#.][\w\\-]+/; -const rePlainSelectorEx = /^[^#.\[(]+([#.][\w-]+)|([#.][\w-]+)$/; +const rePlainSelectorEx = /^[^#.[(]+([#.][\w-]+)|([#.][\w-]+)$/; const rePlainSelectorEscaped = /^[#.](?:\\[0-9A-Fa-f]+ |\\.|\w|-)+/; const reEscapeSequence = /\\([0-9A-Fa-f]+ |.)/g; @@ -91,6 +90,39 @@ const keyFromSelector = selector => { /******************************************************************************/ +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(); + } + context.genericHighCosmeticFilters.add(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 = []); + } + bucket.push(selector); +} + +/******************************************************************************/ + function addExtendedToDNR(context, parser) { if ( parser.isExtendedFilter() === false ) { return false; } @@ -106,6 +138,7 @@ function addExtendedToDNR(context, parser) { for ( const { hn, not, bad } of parser.getExtFilterDomainIterator() ) { if ( bad ) { continue; } if ( exception ) { continue; } + if ( isRegex(hn) ) { continue; } let details = context.scriptletFilters.get(argsToken); if ( details === undefined ) { context.scriptletFilters.set(argsToken, details = { args }); @@ -163,6 +196,7 @@ function addExtendedToDNR(context, parser) { }; for ( const { hn, not, bad } of parser.getExtFilterDomainIterator() ) { if ( bad ) { continue; } + if ( isRegex(hn) ) { continue; } if ( not ) { if ( rule.condition.excludedInitiatorDomains === undefined ) { rule.condition.excludedInitiatorDomains = []; @@ -194,35 +228,8 @@ function addExtendedToDNR(context, parser) { // Generic cosmetic filtering if ( parser.hasOptions() === false ) { - const { compiled } = parser.result; - if ( compiled === undefined ) { return; } - if ( compiled.length <= 1 ) { return; } - if ( parser.isException() ) { - if ( context.genericCosmeticExceptions === undefined ) { - context.genericCosmeticExceptions = new Set(); - } - context.genericCosmeticExceptions.add(compiled); - return; - } - if ( compiled.charCodeAt(0) === 0x7B /* '{' */ ) { return; } - const key = keyFromSelector(compiled); - if ( key === undefined ) { - if ( context.genericHighCosmeticFilters === undefined ) { - context.genericHighCosmeticFilters = new Set(); - } - context.genericHighCosmeticFilters.add(compiled); - 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 = []); - } - bucket.push(compiled); + const { compiled, exception } = parser.result; + addGenericCosmeticFilter(context, compiled, exception); return; } @@ -233,25 +240,22 @@ function addExtendedToDNR(context, parser) { if ( context.specificCosmeticFilters === undefined ) { context.specificCosmeticFilters = new Map(); } + const { compiled, exception, raw } = parser.result; + if ( compiled === undefined ) { + context.specificCosmeticFilters.set(`Invalid filter: ...##${raw}`, { + rejected: true + }); + return; + } + let details = context.specificCosmeticFilters.get(compiled); for ( const { hn, not, bad } of parser.getExtFilterDomainIterator() ) { if ( bad ) { continue; } - let { compiled, exception, raw } = parser.result; - if ( exception ) { continue; } - let rejected; - if ( compiled === undefined ) { - rejected = `Invalid filter: ${hn}##${raw}`; - } - if ( rejected ) { - compiled = rejected; - } - let details = context.specificCosmeticFilters.get(compiled); + if ( not && exception ) { continue; } + if ( isRegex(hn) ) { continue; } if ( details === undefined ) { - details = {}; - if ( rejected ) { details.rejected = true; } - context.specificCosmeticFilters.set(compiled, details); + context.specificCosmeticFilters.set(compiled, details = {}); } - if ( rejected ) { continue; } - if ( not ) { + if ( exception ) { if ( details.excludeMatches === undefined ) { details.excludeMatches = []; } @@ -268,6 +272,13 @@ function addExtendedToDNR(context, parser) { } 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; + } } /******************************************************************************/ @@ -282,6 +293,7 @@ function addToDNR(context, list) { toDNR: true, nativeCssHas: env.includes('native_css_has'), badTypes: [ sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE ], + trustedSource: list.trustedSource || undefined, }); const compiler = staticNetFilteringEngine.createCompiler(); @@ -438,9 +450,9 @@ function finalizeRuleset(context, network) { } }; mergeRules(rulesetMap, 'resourceTypes'); + mergeRules(rulesetMap, 'removeParams'); mergeRules(rulesetMap, 'initiatorDomains'); mergeRules(rulesetMap, 'requestDomains'); - mergeRules(rulesetMap, 'removeParams'); mergeRules(rulesetMap, 'responseHeaders'); // Patch id diff --git a/src/js/static-filtering-parser.js b/src/js/static-filtering-parser.js index 48c5f62e7aaf1..d3b4ca48416cf 100644 --- a/src/js/static-filtering-parser.js +++ b/src/js/static-filtering-parser.js @@ -19,12 +19,11 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ -import Regex from '../lib/regexanalyzer/regex.js'; import * as cssTree from '../lib/csstree/css-tree.js'; +import { ArglistParser } from './arglist-parser.js'; +import Regex from '../lib/regexanalyzer/regex.js'; /******************************************************************************* * @@ -174,6 +173,7 @@ export const NODE_TYPE_NET_OPTION_NAME_IMAGE = iota++; export const NODE_TYPE_NET_OPTION_NAME_IMPORTANT = iota++; export const NODE_TYPE_NET_OPTION_NAME_INLINEFONT = iota++; export const NODE_TYPE_NET_OPTION_NAME_INLINESCRIPT = iota++; +export const NODE_TYPE_NET_OPTION_NAME_IPADDRESS = iota++; export const NODE_TYPE_NET_OPTION_NAME_MATCHCASE = iota++; export const NODE_TYPE_NET_OPTION_NAME_MEDIA = iota++; export const NODE_TYPE_NET_OPTION_NAME_METHOD = iota++; @@ -192,11 +192,13 @@ export const NODE_TYPE_NET_OPTION_NAME_REPLACE = iota++; export const NODE_TYPE_NET_OPTION_NAME_SCRIPT = iota++; export const NODE_TYPE_NET_OPTION_NAME_SHIDE = iota++; export const NODE_TYPE_NET_OPTION_NAME_TO = iota++; +export const NODE_TYPE_NET_OPTION_NAME_URLSKIP = iota++; export const NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM = iota++; export const NODE_TYPE_NET_OPTION_NAME_XHR = iota++; export const NODE_TYPE_NET_OPTION_NAME_WEBRTC = iota++; export const NODE_TYPE_NET_OPTION_NAME_WEBSOCKET = iota++; export const NODE_TYPE_NET_OPTION_ASSIGN = iota++; +export const NODE_TYPE_NET_OPTION_QUOTE = iota++; export const NODE_TYPE_NET_OPTION_VALUE = iota++; export const NODE_TYPE_OPTION_VALUE_DOMAIN_LIST = iota++; export const NODE_TYPE_OPTION_VALUE_DOMAIN_RAW = iota++; @@ -250,6 +252,7 @@ export const nodeTypeFromOptionName = new Map([ [ 'important', NODE_TYPE_NET_OPTION_NAME_IMPORTANT ], [ 'inline-font', NODE_TYPE_NET_OPTION_NAME_INLINEFONT ], [ 'inline-script', NODE_TYPE_NET_OPTION_NAME_INLINESCRIPT ], + [ 'ipaddress', NODE_TYPE_NET_OPTION_NAME_IPADDRESS ], [ 'match-case', NODE_TYPE_NET_OPTION_NAME_MATCHCASE ], [ 'media', NODE_TYPE_NET_OPTION_NAME_MEDIA ], [ 'method', NODE_TYPE_NET_OPTION_NAME_METHOD ], @@ -273,6 +276,7 @@ export const nodeTypeFromOptionName = new Map([ [ 'shide', NODE_TYPE_NET_OPTION_NAME_SHIDE ], /* synonym */ [ 'specifichide', NODE_TYPE_NET_OPTION_NAME_SHIDE ], [ 'to', NODE_TYPE_NET_OPTION_NAME_TO ], + [ 'urlskip', NODE_TYPE_NET_OPTION_NAME_URLSKIP ], [ 'uritransform', NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM ], [ 'xhr', NODE_TYPE_NET_OPTION_NAME_XHR ], /* synonym */ [ 'xmlhttprequest', NODE_TYPE_NET_OPTION_NAME_XHR ], @@ -577,6 +581,7 @@ export const preparserIfTokens = new Set([ 'env_mv3', 'env_safari', 'cap_html_filtering', + 'cap_ipaddress', 'cap_user_stylesheet', 'false', 'ext_abp', @@ -602,102 +607,6 @@ const exCharCodeAt = (s, i) => { /******************************************************************************/ -class ArgListParser { - constructor(separatorChar = ',', mustQuote = false) { - this.separatorChar = this.actualSeparatorChar = separatorChar; - this.separatorCode = this.actualSeparatorCode = separatorChar.charCodeAt(0); - this.mustQuote = mustQuote; - this.quoteBeg = 0; this.quoteEnd = 0; - this.argBeg = 0; this.argEnd = 0; - this.separatorBeg = 0; this.separatorEnd = 0; - this.transform = false; - this.failed = false; - this.reWhitespaceStart = /^\s+/; - this.reWhitespaceEnd = /\s+$/; - this.reOddTrailingEscape = /(?:^|[^\\])(?:\\\\)*\\$/; - this.reTrailingEscapeChars = /\\+$/; - } - nextArg(pattern, beg = 0) { - const len = pattern.length; - this.quoteBeg = beg + this.leftWhitespaceCount(pattern.slice(beg)); - this.failed = false; - const qc = pattern.charCodeAt(this.quoteBeg); - if ( qc === 0x22 /* " */ || qc === 0x27 /* ' */ || qc === 0x60 /* ` */ ) { - this.indexOfNextArgSeparator(pattern, qc); - if ( this.argEnd !== len ) { - this.quoteEnd = this.argEnd + 1; - this.separatorBeg = this.separatorEnd = this.quoteEnd; - this.separatorEnd += this.leftWhitespaceCount(pattern.slice(this.quoteEnd)); - if ( this.separatorEnd === len ) { return this; } - if ( pattern.charCodeAt(this.separatorEnd) === this.separatorCode ) { - this.separatorEnd += 1; - return this; - } - } - } - this.indexOfNextArgSeparator(pattern, this.separatorCode); - this.separatorBeg = this.separatorEnd = this.argEnd; - if ( this.separatorBeg < len ) { - this.separatorEnd += 1; - } - this.argEnd -= this.rightWhitespaceCount(pattern.slice(0, this.separatorBeg)); - this.quoteEnd = this.argEnd; - if ( this.mustQuote ) { - this.failed = true; - } - return this; - } - normalizeArg(s, char = '') { - if ( char === '' ) { char = this.actualSeparatorChar; } - let out = ''; - let pos = 0; - while ( (pos = s.lastIndexOf(char)) !== -1 ) { - out = s.slice(pos) + out; - s = s.slice(0, pos); - const match = this.reTrailingEscapeChars.exec(s); - if ( match === null ) { continue; } - const tail = (match[0].length & 1) !== 0 - ? match[0].slice(0, -1) - : match[0]; - out = tail + out; - s = s.slice(0, -match[0].length); - } - if ( out === '' ) { return s; } - return s + out; - } - leftWhitespaceCount(s) { - const match = this.reWhitespaceStart.exec(s); - return match === null ? 0 : match[0].length; - } - rightWhitespaceCount(s) { - const match = this.reWhitespaceEnd.exec(s); - return match === null ? 0 : match[0].length; - } - indexOfNextArgSeparator(pattern, separatorCode) { - this.argBeg = this.argEnd = separatorCode !== this.separatorCode - ? this.quoteBeg + 1 - : this.quoteBeg; - this.transform = false; - if ( separatorCode !== this.actualSeparatorCode ) { - this.actualSeparatorCode = separatorCode; - this.actualSeparatorChar = String.fromCharCode(separatorCode); - } - while ( this.argEnd < pattern.length ) { - const pos = pattern.indexOf(this.actualSeparatorChar, this.argEnd); - if ( pos === -1 ) { - return (this.argEnd = pattern.length); - } - if ( this.reOddTrailingEscape.test(pattern.slice(0, pos)) === false ) { - return (this.argEnd = pos); - } - this.transform = true; - this.argEnd = pos + 1; - } - } -} - -/******************************************************************************/ - class AstWalker { constructor(parser, from = 0) { this.parser = parser; @@ -781,21 +690,21 @@ class DomainListIterator { let ready = false; while ( node !== 0 ) { switch ( this.parser.getNodeType(node) ) { - case NODE_TYPE_OPTION_VALUE_DOMAIN_RAW: - this.item.hn = ''; - this.item.not = false; - this.item.bad = this.parser.getNodeFlags(node, NODE_FLAG_ERROR) !== 0; - break; - case NODE_TYPE_OPTION_VALUE_NOT: - this.item.not = true; - break; - case NODE_TYPE_OPTION_VALUE_DOMAIN: - this.item.hn = this.parser.getNodeTransform(node); - this.value = this.item; - ready = true; - break; - default: - break; + case NODE_TYPE_OPTION_VALUE_DOMAIN_RAW: + this.item.hn = ''; + this.item.not = false; + this.item.bad = this.parser.getNodeFlags(node, NODE_FLAG_ERROR) !== 0; + break; + case NODE_TYPE_OPTION_VALUE_NOT: + this.item.not = true; + break; + case NODE_TYPE_OPTION_VALUE_DOMAIN: + this.item.hn = this.parser.getNodeTransform(node); + this.value = this.item; + ready = true; + break; + default: + break; } node = this.walker.next(); if ( ready ) { return this; } @@ -859,17 +768,17 @@ export class AstFilterParser { this.reInlineComment = /(?:\s+#).*?$/; this.reNetException = /^@@/; this.reNetAnchor = /(?:)\$[^,\w~]/; - this.reHnAnchoredPlainAscii = /^\|\|[0-9a-z%&,\-.\/:;=?_]+$/; + this.reHnAnchoredPlainAscii = /^\|\|[0-9a-z%&,\-./:;=?_]+$/; this.reHnAnchoredHostnameAscii = /^\|\|(?:[\da-z][\da-z_-]*\.)*[\da-z_-]*[\da-z]\^$/; this.reHnAnchoredHostnameUnicode = /^\|\|(?:[\p{L}\p{N}][\p{L}\p{N}\u{2d}]*\.)*[\p{L}\p{N}\u{2d}]*[\p{L}\p{N}]\^$/u; this.reHn3pAnchoredHostnameAscii = /^\|\|(?:[\da-z][\da-z_-]*\.)*[\da-z_-]*[\da-z]\^\$third-party$/; - this.rePlainAscii = /^[0-9a-z%&\-.\/:;=?_]{2,}$/; + this.rePlainAscii = /^[0-9a-z%&\-./:;=?_]{2,}$/; this.reNetHosts1 = /^127\.0\.0\.1 (?:[\da-z][\da-z_-]*\.)+[\da-z-]*[a-z]$/; this.reNetHosts2 = /^0\.0\.0\.0 (?:[\da-z][\da-z_-]*\.)+[\da-z-]*[a-z]$/; this.rePlainGenericCosmetic = /^##[.#][A-Za-z_][\w-]*$/; this.reHostnameAscii = /^(?:[\da-z][\da-z_-]*\.)*[\da-z][\da-z-]*[\da-z]$/; this.rePlainEntity = /^(?:[\da-z][\da-z_-]*\.)+\*$/; - this.reHostsSink = /^[\w%.:\[\]-]+\s+/; + this.reHostsSink = /^[\w%.:[\]-]+\s+/; this.reHostsRedirect = /(?:0\.0\.0\.0|broadcasthost|local|localhost(?:\.localdomain)?|ip6-\w+)(?:[^\w.-]|$)/; this.reNetOptionComma = /,(?:~?[13a-z-]+(?:=.*?)?|_+)(?:,|$)/; this.rePointlessLeftAnchor = /^\|\|?\*+/; @@ -886,8 +795,8 @@ export class AstFilterParser { this.rePreparseDirectiveIf = /^!#if /; this.rePreparseDirectiveAny = /^!#(?:else|endif|if |include )/; this.reURL = /\bhttps?:\/\/\S+/; - this.reHasPatternSpecialChars = /[\*\^]/; - this.rePatternAllSpecialChars = /[\*\^]+|[^\x00-\x7f]+/g; + this.reHasPatternSpecialChars = /[*^]/; + this.rePatternAllSpecialChars = /[*^]+|[^\x00-\x7f]+/g; // https://github.com/uBlockOrigin/uBlock-issues/issues/1146 // From https://codemirror.net/doc/manual.html#option_specialChars this.reHasInvalidChar = /[\x00-\x1F\x7F-\x9F\xAD\u061C\u200B-\u200F\u2028\u2029\uFEFF\uFFF9-\uFFFC]/; @@ -898,8 +807,10 @@ export class AstFilterParser { 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.scriptletArgListParser = new ArgListParser(','); + this.netOptionValueParser = new ArglistParser(','); + this.scriptletArgListParser = new ArglistParser(','); } finish() { @@ -1315,218 +1226,242 @@ export class AstFilterParser { const hasValue = (flags & NODE_FLAG_OPTION_HAS_VALUE) !== 0; bad = false; realBad = false; switch ( type ) { - case NODE_TYPE_NET_OPTION_NAME_ALL: - realBad = isNegated || hasValue || modifierType !== 0; - break; - case NODE_TYPE_NET_OPTION_NAME_1P: - case NODE_TYPE_NET_OPTION_NAME_3P: - realBad = hasValue; - break; - case NODE_TYPE_NET_OPTION_NAME_BADFILTER: - badfilter = true; - /* falls through */ - case NODE_TYPE_NET_OPTION_NAME_NOOP: - realBad = isNegated || hasValue; - break; - case NODE_TYPE_NET_OPTION_NAME_CSS: - 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: - realBad = hasValue; - if ( realBad ) { break; } - requestTypeCount += 1; - break; - case NODE_TYPE_NET_OPTION_NAME_CNAME: - realBad = isException === false || isNegated || hasValue; - if ( realBad ) { break; } - modifierType = type; - break; - case NODE_TYPE_NET_OPTION_NAME_CSP: - realBad = (hasValue || isException) === false || - modifierType !== 0 || - this.reBadCSP.test( - this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_CSP) - ); - if ( realBad ) { break; } - modifierType = type; - break; - case NODE_TYPE_NET_OPTION_NAME_DENYALLOW: - realBad = isNegated || hasValue === false || - this.getBranchFromType(NODE_TYPE_NET_OPTION_NAME_FROM) === 0; - break; - case NODE_TYPE_NET_OPTION_NAME_DOC: - case NODE_TYPE_NET_OPTION_NAME_FRAME: - realBad = hasValue; - if ( realBad ) { break; } - docTypeCount += 1; - break; - case NODE_TYPE_NET_OPTION_NAME_EHIDE: - case NODE_TYPE_NET_OPTION_NAME_GHIDE: - case NODE_TYPE_NET_OPTION_NAME_SHIDE: - realBad = isNegated || hasValue || modifierType !== 0; - if ( realBad ) { break; } - behaviorTypeCount += 1; - unredirectableTypeCount += 1; - break; - case NODE_TYPE_NET_OPTION_NAME_EMPTY: - case NODE_TYPE_NET_OPTION_NAME_MP4: - realBad = isNegated || hasValue || modifierType !== 0; - if ( realBad ) { break; } - modifierType = type; - break; - case NODE_TYPE_NET_OPTION_NAME_FROM: - case NODE_TYPE_NET_OPTION_NAME_METHOD: - case NODE_TYPE_NET_OPTION_NAME_TO: - realBad = isNegated || hasValue === false; - break; - case NODE_TYPE_NET_OPTION_NAME_GENERICBLOCK: - bad = true; - realBad = isException === false || isNegated || hasValue; - break; - case NODE_TYPE_NET_OPTION_NAME_HEADER: - realBad = isNegated || hasValue === false; - break; - case NODE_TYPE_NET_OPTION_NAME_IMPORTANT: - realBad = isException || isNegated || hasValue; - break; - case NODE_TYPE_NET_OPTION_NAME_INLINEFONT: - case NODE_TYPE_NET_OPTION_NAME_INLINESCRIPT: - realBad = hasValue; - if ( realBad ) { break; } - modifierType = type; - unredirectableTypeCount += 1; - break; - case NODE_TYPE_NET_OPTION_NAME_MATCHCASE: - realBad = this.isRegexPattern() === false; - break; - case NODE_TYPE_NET_OPTION_NAME_PERMISSIONS: - realBad = modifierType !== 0 || - (hasValue || isException) === false || - this.reBadPP.test( - this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_PERMISSIONS) - ); - if ( realBad ) { break; } - modifierType = type; - break; - case NODE_TYPE_NET_OPTION_NAME_PING: - case NODE_TYPE_NET_OPTION_NAME_WEBSOCKET: - realBad = hasValue; - if ( realBad ) { break; } - requestTypeCount += 1; - unredirectableTypeCount += 1; - break; - case NODE_TYPE_NET_OPTION_NAME_POPUNDER: - case NODE_TYPE_NET_OPTION_NAME_POPUP: - realBad = hasValue; - if ( realBad ) { break; } - abstractTypeCount += 1; - unredirectableTypeCount += 1; - break; - case NODE_TYPE_NET_OPTION_NAME_REDIRECT: - case NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE: - case NODE_TYPE_NET_OPTION_NAME_REPLACE: - case NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM: - realBad = isNegated || (isException || hasValue) === false || - modifierType !== 0; - if ( realBad ) { break; } - modifierType = type; - break; - case NODE_TYPE_NET_OPTION_NAME_REMOVEPARAM: - realBad = isNegated || modifierType !== 0; - if ( realBad ) { break; } - modifierType = type; - break; - case NODE_TYPE_NET_OPTION_NAME_STRICT1P: - case NODE_TYPE_NET_OPTION_NAME_STRICT3P: - realBad = isNegated || hasValue; - break; - case NODE_TYPE_NET_OPTION_NAME_UNKNOWN: - this.astError = AST_ERROR_OPTION_UNKNOWN; - realBad = true; - break; - case NODE_TYPE_NET_OPTION_NAME_WEBRTC: - realBad = true; - break; - case NODE_TYPE_NET_PATTERN_RAW: - realBad = this.hasOptions() === false && - this.getNetPattern().length <= 1; - break; - default: - break; - } - if ( bad || realBad ) { - this.addNodeFlags(targetNode, NODE_FLAG_ERROR); - } - if ( realBad ) { - this.addFlags(AST_FLAG_HAS_ERROR); - } - } - const requiresTrustedSource = ( ) => - this.options.trustedSource !== true && - isException === false && badfilter === false; - switch ( modifierType ) { + case NODE_TYPE_NET_OPTION_NAME_ALL: + realBad = isNegated || hasValue || modifierType !== 0; + break; + case NODE_TYPE_NET_OPTION_NAME_1P: + case NODE_TYPE_NET_OPTION_NAME_3P: + realBad = hasValue; + break; + case NODE_TYPE_NET_OPTION_NAME_BADFILTER: + badfilter = true; + /* falls through */ + case NODE_TYPE_NET_OPTION_NAME_NOOP: + realBad = isNegated || hasValue; + break; + case NODE_TYPE_NET_OPTION_NAME_CSS: + 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: + realBad = hasValue; + if ( realBad ) { break; } + requestTypeCount += 1; + break; case NODE_TYPE_NET_OPTION_NAME_CNAME: - realBad = abstractTypeCount || behaviorTypeCount || requestTypeCount; + realBad = isException === false || isNegated || hasValue; + if ( realBad ) { break; } + modifierType = type; break; case NODE_TYPE_NET_OPTION_NAME_CSP: - case NODE_TYPE_NET_OPTION_NAME_PERMISSIONS: - realBad = abstractTypeCount || behaviorTypeCount || requestTypeCount; + realBad = (hasValue || isException) === false || + modifierType !== 0 || + this.reBadCSP.test( + this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_CSP) + ); + if ( realBad ) { break; } + modifierType = type; break; - case NODE_TYPE_NET_OPTION_NAME_INLINEFONT: - case NODE_TYPE_NET_OPTION_NAME_INLINESCRIPT: - realBad = behaviorTypeCount; + case NODE_TYPE_NET_OPTION_NAME_DENYALLOW: + realBad = isNegated || hasValue === false || + this.getBranchFromType(NODE_TYPE_NET_OPTION_NAME_FROM) === 0; break; - case NODE_TYPE_NET_OPTION_NAME_EMPTY: - realBad = abstractTypeCount || behaviorTypeCount; + case NODE_TYPE_NET_OPTION_NAME_DOC: + case NODE_TYPE_NET_OPTION_NAME_FRAME: + realBad = hasValue; + if ( realBad ) { break; } + docTypeCount += 1; break; - case NODE_TYPE_NET_OPTION_NAME_MEDIA: + case NODE_TYPE_NET_OPTION_NAME_EHIDE: + case NODE_TYPE_NET_OPTION_NAME_GHIDE: + case NODE_TYPE_NET_OPTION_NAME_SHIDE: + realBad = isNegated || hasValue || modifierType !== 0; + if ( realBad ) { break; } + behaviorTypeCount += 1; + unredirectableTypeCount += 1; + break; + case NODE_TYPE_NET_OPTION_NAME_EMPTY: case NODE_TYPE_NET_OPTION_NAME_MP4: - realBad = abstractTypeCount || behaviorTypeCount || docTypeCount || requestTypeCount; + realBad = isNegated || hasValue || modifierType !== 0; + if ( realBad ) { break; } + modifierType = type; break; - case NODE_TYPE_NET_OPTION_NAME_REDIRECT: - case NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE: { - realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount; + case NODE_TYPE_NET_OPTION_NAME_FROM: + case NODE_TYPE_NET_OPTION_NAME_METHOD: + case NODE_TYPE_NET_OPTION_NAME_TO: + realBad = isNegated || hasValue === false; break; - } - case NODE_TYPE_NET_OPTION_NAME_REPLACE: { - realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount; + case NODE_TYPE_NET_OPTION_NAME_GENERICBLOCK: + bad = true; + realBad = isException === false || isNegated || hasValue; + break; + case NODE_TYPE_NET_OPTION_NAME_HEADER: + realBad = isNegated || hasValue === false; + break; + case NODE_TYPE_NET_OPTION_NAME_IMPORTANT: + realBad = isException || isNegated || hasValue; + break; + case NODE_TYPE_NET_OPTION_NAME_INLINEFONT: + case NODE_TYPE_NET_OPTION_NAME_INLINESCRIPT: + realBad = hasValue; if ( realBad ) { break; } - if ( requiresTrustedSource() ) { - this.astError = AST_ERROR_UNTRUSTED_SOURCE; - realBad = true; - break; - } - const value = this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_REPLACE); - if ( parseReplaceValue(value) === undefined ) { - this.astError = AST_ERROR_OPTION_BADVALUE; - realBad = true; + modifierType = type; + unredirectableTypeCount += 1; + break; + case NODE_TYPE_NET_OPTION_NAME_IPADDRESS: { + const value = this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_IPADDRESS); + if ( /^\/.+\/$/.test(value) ) { + try { void new RegExp(value); } + catch(_) { realBad = true; } } break; } - case NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM: { - realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount; + case NODE_TYPE_NET_OPTION_NAME_MATCHCASE: + realBad = this.isRegexPattern() === false; + break; + case NODE_TYPE_NET_OPTION_NAME_PERMISSIONS: + realBad = modifierType !== 0 || + (hasValue || isException) === false || + this.reBadPP.test( + this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_PERMISSIONS) + ); if ( realBad ) { break; } - if ( requiresTrustedSource() ) { - this.astError = AST_ERROR_UNTRUSTED_SOURCE; - realBad = true; - break; - } - const value = this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM); - if ( value !== '' && parseReplaceValue(value) === undefined ) { - this.astError = AST_ERROR_OPTION_BADVALUE; - realBad = true; - } + modifierType = type; + break; + case NODE_TYPE_NET_OPTION_NAME_PING: + case NODE_TYPE_NET_OPTION_NAME_WEBSOCKET: + realBad = hasValue; + if ( realBad ) { break; } + requestTypeCount += 1; + unredirectableTypeCount += 1; + break; + case NODE_TYPE_NET_OPTION_NAME_POPUNDER: + case NODE_TYPE_NET_OPTION_NAME_POPUP: + realBad = hasValue; + if ( realBad ) { break; } + abstractTypeCount += 1; + unredirectableTypeCount += 1; + break; + case NODE_TYPE_NET_OPTION_NAME_REDIRECT: + case NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE: + case NODE_TYPE_NET_OPTION_NAME_REPLACE: + case NODE_TYPE_NET_OPTION_NAME_URLSKIP: + case NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM: + realBad = isNegated || (isException || hasValue) === false || + modifierType !== 0; + if ( realBad ) { break; } + modifierType = type; break; - } case NODE_TYPE_NET_OPTION_NAME_REMOVEPARAM: - realBad = abstractTypeCount || behaviorTypeCount; + realBad = isNegated || modifierType !== 0; + if ( realBad ) { break; } + modifierType = type; + break; + case NODE_TYPE_NET_OPTION_NAME_STRICT1P: + case NODE_TYPE_NET_OPTION_NAME_STRICT3P: + realBad = isNegated || hasValue; + break; + case NODE_TYPE_NET_OPTION_NAME_UNKNOWN: + this.astError = AST_ERROR_OPTION_UNKNOWN; + realBad = true; + break; + case NODE_TYPE_NET_OPTION_NAME_WEBRTC: + realBad = true; + break; + case NODE_TYPE_NET_PATTERN_RAW: + realBad = this.hasOptions() === false && + this.getNetPattern().length <= 1; break; default: break; + } + if ( bad || realBad ) { + this.addNodeFlags(targetNode, NODE_FLAG_ERROR); + } + if ( realBad ) { + 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; + break; + case NODE_TYPE_NET_OPTION_NAME_CSP: + case NODE_TYPE_NET_OPTION_NAME_PERMISSIONS: + realBad = abstractTypeCount || behaviorTypeCount || requestTypeCount; + break; + case NODE_TYPE_NET_OPTION_NAME_INLINEFONT: + case NODE_TYPE_NET_OPTION_NAME_INLINESCRIPT: + realBad = behaviorTypeCount; + break; + case NODE_TYPE_NET_OPTION_NAME_EMPTY: + realBad = abstractTypeCount || behaviorTypeCount; + break; + case NODE_TYPE_NET_OPTION_NAME_MEDIA: + case NODE_TYPE_NET_OPTION_NAME_MP4: + realBad = abstractTypeCount || behaviorTypeCount || docTypeCount || requestTypeCount; + break; + case NODE_TYPE_NET_OPTION_NAME_REDIRECT: + case NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE: { + realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount; + break; + } + case NODE_TYPE_NET_OPTION_NAME_REPLACE: { + realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount; + if ( realBad ) { break; } + if ( requiresTrustedSource() ) { + this.astError = AST_ERROR_UNTRUSTED_SOURCE; + realBad = true; + break; + } + const value = this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_REPLACE); + if ( parseReplaceValue(value) === undefined ) { + this.astError = AST_ERROR_OPTION_BADVALUE; + realBad = true; + } + break; + } + case NODE_TYPE_NET_OPTION_NAME_URLSKIP: { + realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount; + if ( realBad ) { break; } + if ( requiresTrustedSource() ) { + this.astError = AST_ERROR_UNTRUSTED_SOURCE; + realBad = true; + break; + } + const value = this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_URLSKIP); + if ( value.length < 2 ) { + this.astError = AST_ERROR_OPTION_BADVALUE; + realBad = true; + } + break; + } + case NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM: { + realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount; + if ( realBad ) { break; } + if ( requiresTrustedSource() ) { + this.astError = AST_ERROR_UNTRUSTED_SOURCE; + realBad = true; + break; + } + const value = this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM); + if ( value !== '' && parseReplaceValue(value) === undefined ) { + this.astError = AST_ERROR_OPTION_BADVALUE; + realBad = true; + } + break; + } + case NODE_TYPE_NET_OPTION_NAME_REMOVEPARAM: + realBad = abstractTypeCount || behaviorTypeCount; + break; + default: + break; } if ( realBad ) { const targetNode = this.getBranchFromType(modifierType); @@ -1542,18 +1477,15 @@ export class AstFilterParser { if ( j === -1 ) { return end; } if ( (j+1) === end ) { return end; } for (;;) { - const before = s.charCodeAt(j-1); - if ( j !== start && before === 0x24 /* $ */ ) { return -1; } - const after = s.charCodeAt(j+1); - if ( - after !== 0x29 /* ) */ && - after !== 0x2F /* / */ && - after !== 0x7C /* | */ && - before !== 0x5C /* \ */ - ) { - return j; + 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 ( j === start ) { break; } j = s.lastIndexOf('$', j-1); if ( j === -1 ) { break; } } @@ -1958,19 +1890,21 @@ export class AstFilterParser { if ( parentEnd === parentBeg ) { return 0; } const s = this.getNodeString(parent); const optionsEnd = s.length; + const parseDetails = { node: 0, len: 0 }; const head = this.allocHeadNode(); let prev = head, next = 0; let optionBeg = 0, optionEnd = 0; - let emptyOption = false, badComma = false; while ( optionBeg !== optionsEnd ) { - optionEnd = this.endOfNetOption(s, optionBeg); next = this.allocTypedNode( NODE_TYPE_NET_OPTION_RAW, parentBeg + optionBeg, - parentBeg + optionEnd + parentBeg + optionsEnd // open ended ); - emptyOption = optionEnd === optionBeg; - this.linkDown(next, this.parseNetOption(next)); + this.parseNetOption(next, parseDetails); + // set next's end to down's end + optionEnd += parseDetails.len; + this.nodes[next+NODE_END_INDEX] = parentBeg + optionEnd; + this.linkDown(next, parseDetails.node); prev = this.linkRight(prev, next); if ( optionEnd === optionsEnd ) { break; } optionBeg = optionEnd + 1; @@ -1979,12 +1913,12 @@ export class AstFilterParser { parentBeg + optionEnd, parentBeg + optionBeg ); - badComma = optionBeg === optionsEnd; - prev = this.linkRight(prev, next); - if ( emptyOption || badComma ) { + if ( parseDetails.len === 0 || optionBeg === optionsEnd ) { this.addNodeFlags(next, NODE_FLAG_ERROR); this.addFlags(AST_FLAG_HAS_ERROR); } + prev = this.linkRight(prev, next); + optionEnd = optionBeg; } this.linkRight(prev, this.allocSentinelNode(NODE_TYPE_NET_OPTION_SENTINEL, parentEnd) @@ -1992,19 +1926,23 @@ export class AstFilterParser { return this.throwHeadNode(head); } - endOfNetOption(s, beg) { - const match = this.reNetOptionComma.exec(s.slice(beg)); - return match !== null ? beg + match.index : s.length; - } - - parseNetOption(parent) { + parseNetOption(parent, parseDetails) { const parentBeg = this.nodes[parent+NODE_BEG_INDEX]; const s = this.getNodeString(parent); - const optionEnd = s.length; + const match = this.reNetOption.exec(s) || []; + if ( match.length === 0 ) { + this.addNodeFlags(parent, NODE_FLAG_ERROR); + this.addFlags(AST_FLAG_HAS_ERROR); + this.astError = AST_ERROR_OPTION_UNKNOWN; + parseDetails.node = 0; + parseDetails.len = s.length; + return; + } const head = this.allocHeadNode(); let prev = head, next = 0; - let nameBeg = 0; - if ( s.charCodeAt(0) === 0x7E ) { + const matchEnd = match && match[0].length || 0; + const negated = match[1] === '~'; + if ( negated ) { this.addNodeFlags(parent, NODE_FLAG_IS_NEGATED); next = this.allocTypedNode( NODE_TYPE_NET_OPTION_NAME_NOT, @@ -2012,11 +1950,11 @@ export class AstFilterParser { parentBeg+1 ); prev = this.linkRight(prev, next); - nameBeg += 1; } - const equalPos = s.indexOf('='); - const nameEnd = equalPos !== -1 ? equalPos : s.length; - const name = s.slice(nameBeg, nameEnd); + const nameBeg = negated ? 1 : 0; + const assigned = match[3] === '='; + const nameEnd = matchEnd - (assigned ? 1 : 0); + const name = match[2] || ''; let nodeOptionType = nodeTypeFromOptionName.get(name); if ( nodeOptionType === undefined ) { nodeOptionType = this.reNoopOption.test(name) @@ -2039,40 +1977,72 @@ export class AstFilterParser { this.addNodeToRegister(nodeOptionType, parent); } prev = this.linkRight(prev, next); - if ( equalPos === -1 ) { - return this.throwHeadNode(head); + if ( assigned === false ) { + parseDetails.node = this.throwHeadNode(head); + parseDetails.len = matchEnd; + return; } - const valueBeg = equalPos + 1; next = this.allocTypedNode( NODE_TYPE_NET_OPTION_ASSIGN, - parentBeg + equalPos, - parentBeg + valueBeg + parentBeg + matchEnd - 1, + parentBeg + matchEnd ); prev = this.linkRight(prev, next); - if ( (equalPos+1) === optionEnd ) { - this.addNodeFlags(parent, NODE_FLAG_ERROR); - this.addFlags(AST_FLAG_HAS_ERROR); - return this.throwHeadNode(head); - } this.addNodeFlags(parent, NODE_FLAG_OPTION_HAS_VALUE); + const details = this.netOptionValueParser.nextArg(s, matchEnd); + if ( details.quoteBeg !== details.argBeg ) { + next = this.allocTypedNode( + NODE_TYPE_NET_OPTION_QUOTE, + parentBeg + details.quoteBeg, + parentBeg + details.argBeg + ); + prev = this.linkRight(prev, next); + } else { + const argEnd = this.endOfNetOption(s, matchEnd); + if ( argEnd !== details.argEnd ) { + details.argEnd = details.quoteEnd = argEnd; + } + } next = this.allocTypedNode( NODE_TYPE_NET_OPTION_VALUE, - parentBeg + valueBeg, - parentBeg + optionEnd + parentBeg + details.argBeg, + parentBeg + details.argEnd ); + if ( details.argBeg === details.argEnd ) { + this.addNodeFlags(parent, NODE_FLAG_ERROR); + this.addFlags(AST_FLAG_HAS_ERROR); + this.astError = AST_ERROR_OPTION_BADVALUE; + } else if ( details.transform ) { + const arg = s.slice(details.argBeg, details.argEnd); + this.setNodeTransform(next, this.netOptionValueParser.normalizeArg(arg)); + } switch ( nodeOptionType ) { - case NODE_TYPE_NET_OPTION_NAME_DENYALLOW: - this.linkDown(next, this.parseDomainList(next, '|'), 0b00000); - break; - case NODE_TYPE_NET_OPTION_NAME_FROM: - case NODE_TYPE_NET_OPTION_NAME_TO: - this.linkDown(next, this.parseDomainList(next, '|', 0b11010)); - break; - default: - break; + case NODE_TYPE_NET_OPTION_NAME_DENYALLOW: + this.linkDown(next, this.parseDomainList(next, '|'), 0b00000); + break; + case NODE_TYPE_NET_OPTION_NAME_FROM: + case NODE_TYPE_NET_OPTION_NAME_TO: + this.linkDown(next, this.parseDomainList(next, '|', 0b11010)); + break; + default: + break; } - this.linkRight(prev, next); - return this.throwHeadNode(head); + prev = this.linkRight(prev, next); + if ( details.quoteEnd !== details.argEnd ) { + next = this.allocTypedNode( + NODE_TYPE_NET_OPTION_QUOTE, + parentBeg + details.argEnd, + parentBeg + details.quoteEnd + ); + this.linkRight(prev, next); + } + parseDetails.node = this.throwHeadNode(head); + parseDetails.len = details.quoteEnd; + } + + endOfNetOption(s, beg) { + const match = this.reNetOptionComma.exec(s.slice(beg)); + return match !== null ? beg + match.index : s.length; } getNetOptionValue(type) { @@ -2094,32 +2064,26 @@ export class AstFilterParser { ); if ( parentEnd === parentBeg ) { return containerNode; } const separatorCode = separator.charCodeAt(0); + const parseDetails = { separator, mode, node: 0, len: 0 }; const listNode = this.allocHeadNode(); let prev = listNode; let domainNode = 0; let separatorNode = 0; const s = this.getNodeString(parent); const listEnd = s.length; - let beg = 0, end = 0, c = 0; + let beg = 0, end = 0; while ( beg < listEnd ) { - c = s.charCodeAt(beg); - if ( c === 0x7E /* ~ */ ) { - c = s.charCodeAt(beg+1) || 0; - } - if ( c !== 0x2F /* / */ ) { - end = s.indexOf(separator, beg); - } else { - end = s.indexOf('/', beg+1); - end = s.indexOf(separator, end !== -1 ? end+1 : beg); - } - if ( end === -1 ) { end = listEnd; } + const next = this.allocTypedNode( + NODE_TYPE_OPTION_VALUE_DOMAIN_RAW, + parentBeg + beg, + parentBeg + listEnd // open ended + ); + this.parseDomain(next, parseDetails); + end = beg + parseDetails.len; + this.nodes[next+NODE_END_INDEX] = parentBeg + end; if ( end !== beg ) { - domainNode = this.allocTypedNode( - NODE_TYPE_OPTION_VALUE_DOMAIN_RAW, - parentBeg + beg, - parentBeg + end - ); - this.linkDown(domainNode, this.parseDomain(domainNode, mode)); + domainNode = next; + this.linkDown(domainNode, parseDetails.node); prev = this.linkRight(prev, domainNode); } else { domainNode = 0; @@ -2155,23 +2119,38 @@ export class AstFilterParser { return containerNode; } - parseDomain(parent, mode = 0b0000) { + parseDomain(parent, parseDetails) { const parentBeg = this.nodes[parent+NODE_BEG_INDEX]; const parentEnd = this.nodes[parent+NODE_END_INDEX]; + const not = this.charCodeAt(parentBeg) === 0x7E /* ~ */; let head = 0, next = 0; let beg = parentBeg; - const c = this.charCodeAt(beg); - if ( c === 0x7E /* ~ */ ) { + if ( not ) { this.addNodeFlags(parent, NODE_FLAG_IS_NEGATED); head = this.allocTypedNode(NODE_TYPE_OPTION_VALUE_NOT, beg, beg + 1); - if ( (mode & 0b1000) === 0 ) { + if ( (parseDetails.mode & 0b1000) === 0 ) { this.addNodeFlags(parent, NODE_FLAG_ERROR); } beg += 1; } - if ( beg !== parentEnd ) { - next = this.allocTypedNode(NODE_TYPE_OPTION_VALUE_DOMAIN, beg, parentEnd); - const hn = this.normalizeDomainValue(this.getNodeString(next), mode); + const c0 = this.charCodeAt(beg); + let end = beg; + let type = 0; + if ( c0 === 0x2F /* / */ ) { + end = this.indexOf('/', beg + 1, parentEnd); + if ( end !== -1 ) { end += 1; } + type = 1; + } else if ( c0 === 0x5B /* [ */ && this.startsWith('[$domain=/', beg) ) { + end = this.indexOf('/]', beg + 10, parentEnd); + if ( end !== -1 ) { end += 2; } + type = 2; + } 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); if ( hn !== undefined ) { if ( hn !== '' ) { this.setNodeTransform(next, hn); @@ -2190,7 +2169,8 @@ export class AstFilterParser { this.addNodeFlags(parent, NODE_FLAG_ERROR); this.addFlags(AST_FLAG_HAS_ERROR); } - return head; + parseDetails.node = head; + parseDetails.len = end - parentBeg; } // mode bits: @@ -2199,16 +2179,16 @@ export class AstFilterParser { // 0b00100: can use single wildcard // 0b01000: can be negated // 0b10000: can be a regex - normalizeDomainValue(s, modeBits) { - if ( (modeBits & 0b10000) === 0 || - s.length <= 2 || - s.charCodeAt(0) !== 0x2F /* / */ || - exCharCodeAt(s, -1) !== 0x2F /* / */ - ) { + normalizeDomainValue(node, type, modeBits) { + const s = this.getNodeString(node); + if ( type === 0 ) { return this.normalizeHostnameValue(s, modeBits); } - const source = this.normalizeRegexPattern(s); + if ( (modeBits & 0b10000) === 0 ) { return ''; } + const regex = type === 1 ? s : `/${s.slice(10, -2)}/`; + const source = this.normalizeRegexPattern(regex); if ( source === '' ) { return ''; } + if ( type === 1 && source === regex ) { return; } return `/${source}/`; } @@ -2284,27 +2264,27 @@ export class AstFilterParser { if ( (flags & NODE_FLAG_ERROR) !== 0 ) { continue; } realBad = false; switch ( type ) { - case NODE_TYPE_EXT_PATTERN_RESPONSEHEADER: { - const pattern = this.getNodeString(targetNode); - realBad = - pattern !== '' && removableHTTPHeaders.has(pattern) === false || - pattern === '' && isException === false; - break; - } - case NODE_TYPE_EXT_PATTERN_SCRIPTLET_TOKEN: { - if ( this.interactive !== true ) { break; } - if ( isException ) { break; } - const { trustedSource, trustedScriptletTokens } = this.options; - if ( trustedScriptletTokens instanceof Set === false ) { break; } - const token = this.getNodeString(targetNode); - if ( trustedScriptletTokens.has(token) && trustedSource !== true ) { - this.astError = AST_ERROR_UNTRUSTED_SOURCE; - realBad = true; - } - break; + case NODE_TYPE_EXT_PATTERN_RESPONSEHEADER: { + const pattern = this.getNodeString(targetNode); + realBad = + pattern !== '' && removableHTTPHeaders.has(pattern) === false || + pattern === '' && isException === false; + break; + } + case NODE_TYPE_EXT_PATTERN_SCRIPTLET_TOKEN: { + if ( this.interactive !== true ) { break; } + if ( isException ) { break; } + const { trustedSource, trustedScriptletTokens } = this.options; + if ( trustedScriptletTokens instanceof Set === false ) { break; } + const token = this.getNodeString(targetNode); + if ( trustedScriptletTokens.has(token) && trustedSource !== true ) { + this.astError = AST_ERROR_UNTRUSTED_SOURCE; + realBad = true; } - default: - break; + break; + } + default: + break; } if ( realBad ) { this.addNodeFlags(targetNode, NODE_FLAG_ERROR); @@ -2420,7 +2400,7 @@ export class AstFilterParser { parentBeg + argsEnd ); this.linkDown(next, this.parseExtPatternScriptletArglist(next)); - prev = this.linkRight(prev, next); + this.linkRight(prev, next); return this.throwHeadNode(head); } @@ -2474,12 +2454,12 @@ export class AstFilterParser { const walker = this.getWalker(root); for ( let node = walker.next(); node !== 0; node = walker.next() ) { switch ( this.getNodeType(node) ) { - case NODE_TYPE_EXT_PATTERN_SCRIPTLET_TOKEN: - case NODE_TYPE_EXT_PATTERN_SCRIPTLET_ARG: - args.push(this.getNodeTransform(node)); - break; - default: - break; + case NODE_TYPE_EXT_PATTERN_SCRIPTLET_TOKEN: + case NODE_TYPE_EXT_PATTERN_SCRIPTLET_ARG: + args.push(this.getNodeTransform(node)); + break; + default: + break; } } walker.dispose(); @@ -2795,6 +2775,15 @@ export class AstFilterParser { return pos < this.rawEnd ? this.raw.charCodeAt(pos) : -1; } + indexOf(needle, beg, end = 0) { + const haystack = end === 0 ? this.raw : this.raw.slice(0, end); + return haystack.indexOf(needle, beg); + } + + startsWith(s, pos) { + return pos < this.rawEnd && this.raw.startsWith(s, pos); + } + isTokenCharCode(c) { return c === 0x25 || c >= 0x30 && c <= 0x39 || @@ -3013,7 +3002,7 @@ export function parseHeaderValue(arg) { export function parseReplaceValue(s) { if ( s.charCodeAt(0) !== 0x2F /* / */ ) { return; } - const parser = new ArgListParser('/'); + const parser = new ArglistParser('/'); parser.nextArg(s, 1); let pattern = s.slice(parser.argBeg, parser.argEnd); if ( parser.transform ) { @@ -3071,6 +3060,7 @@ export const netOptionTokenDescriptors = new Map([ [ 'important', { blockOnly: true } ], [ 'inline-font', { canNegate: true } ], [ 'inline-script', { canNegate: true } ], + [ 'ipaddress', { mustAssign: true } ], [ 'match-case', { } ], [ 'media', { canNegate: true } ], [ 'method', { mustAssign: true } ], @@ -3088,12 +3078,13 @@ export const netOptionTokenDescriptors = new Map([ /* synonym */ [ 'rewrite', { mustAssign: true } ], [ 'redirect-rule', { mustAssign: true } ], [ 'removeparam', { } ], - [ 'replace', { mustAssign: true } ], /* synonym */ [ 'queryprune', { } ], + [ 'replace', { mustAssign: true } ], [ 'script', { canNegate: true } ], [ 'shide', { } ], /* synonym */ [ 'specifichide', { } ], [ 'to', { mustAssign: true } ], + [ 'urlskip', { mustAssign: true } ], [ 'uritransform', { mustAssign: true } ], [ 'xhr', { canNegate: true } ], /* synonym */ [ 'xmlhttprequest', { canNegate: true } ], @@ -3206,6 +3197,7 @@ class ExtSelectorCompiler { 'matches-css-before', 'matches-media', 'matches-path', + 'matches-prop', 'min-text-length', 'others', 'shadow', @@ -3255,10 +3247,13 @@ class ExtSelectorCompiler { // We have an Adguard/ABP cosmetic filter if and only if the // character is `$`, `%` or `?`, otherwise it's not a cosmetic // filter. - // Adguard's style injection: translate to uBO's format. - if ( compileOptions.adgStyleSyntax === true ) { - raw = this.translateAdguardCSSInjectionFilter(raw); - if ( raw === '' ) { return false; } + // Adguard/EasyList style injection: translate to uBO's format. + if ( this.isStyleInjectionFilter(raw) ) { + const translated = this.translateStyleInjectionFilter(raw); + if ( translated === undefined ) { return false; } + raw = translated; + } else if ( compileOptions.adgStyleSyntax === true ) { + return false; } // Normalize AdGuard's attribute-based procedural operators. @@ -3794,9 +3789,14 @@ class ExtSelectorCompiler { return true; } - translateAdguardCSSInjectionFilter(suffix) { - const matches = /^(.*)\s*\{([^}]+)\}\s*$/.exec(suffix); - if ( matches === null ) { return ''; } + isStyleInjectionFilter(selector) { + const len = selector.length; + return len !== 0 && selector.charCodeAt(len-1) === 0x7D /* } */; + } + + translateStyleInjectionFilter(raw) { + const matches = /^(.+)\s*\{([^}]+)\}$/.exec(raw); + if ( matches === null ) { return; } const selector = matches[1].trim(); const style = matches[2].trim(); // Special style directive `remove: true` is converted into a @@ -3842,6 +3842,7 @@ class ExtSelectorCompiler { case 'if-not': return this.compileSelector(arg); case 'matches-attr': + case 'matches-prop': return this.compileMatchAttrArgument(arg); case 'matches-css': return this.compileCSSDeclaration(arg); @@ -4037,7 +4038,7 @@ class ExtSelectorCompiler { compileAttrList(s) { if ( s === '' ) { return s; } - const attrs = s.split('\s*,\s*'); + const attrs = s.split(/\s*,\s*/); const out = []; for ( const attr of attrs ) { if ( attr !== '' ) { @@ -4050,9 +4051,11 @@ class ExtSelectorCompiler { compileXpathExpression(s) { const r = this.unquoteString(s); if ( r.i !== s.length ) { return; } - if ( globalThis.document instanceof Object === false ) { return r.s; } + const doc = globalThis.document; + if ( doc instanceof Object === false ) { return r.s; } try { - globalThis.document.createExpression(r.s, null); + const expr = doc.createExpression(r.s, null); + expr.evaluate(doc, XPathResult.ANY_UNORDERED_NODE_TYPE); } catch (e) { return; } @@ -4075,6 +4078,7 @@ export const proceduralOperatorTokens = new Map([ [ 'matches-css', 0b11 ], [ 'matches-media', 0b11 ], [ 'matches-path', 0b11 ], + [ 'matches-prop', 0b11 ], [ 'min-text-length', 0b01 ], [ 'not', 0b01 ], [ 'nth-ancestor', 0b00 ], @@ -4288,13 +4292,14 @@ export const utils = (( ) => { [ 'env_safari', 'safari' ], [ 'cap_html_filtering', 'html_filtering' ], [ 'cap_user_stylesheet', 'user_stylesheet' ], + [ 'cap_ipaddress', 'ipaddress' ], [ 'false', 'false' ], // Hoping ABP-only list maintainers can at least make use of it to // help non-ABP content blockers better deal with filters benefiting // only ABP. [ 'ext_abp', 'false' ], // Compatibility with other blockers - // https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#adguard-specific + // https://adguard.com/kb/general/ad-filtering/create-own-filters/#conditions-directive [ 'adguard', 'adguard' ], [ 'adguard_app_android', 'false' ], [ 'adguard_app_ios', 'false' ], @@ -4322,8 +4327,11 @@ export const utils = (( ) => { static evaluateExprToken(token, env = []) { const not = token.charCodeAt(0) === 0x21 /* ! */; if ( not ) { token = token.slice(1); } - const state = preparserTokens.get(token); - if ( state === undefined ) { return; } + let state = preparserTokens.get(token); + if ( state === undefined ) { + if ( token.startsWith('cap_') === false ) { return; } + state = 'false'; + } return state === 'false' && not || env.includes(state) !== not; } @@ -4359,14 +4367,14 @@ export const utils = (( ) => { const parts = [ 0 ]; let discard = false; - const shouldDiscard = ( ) => stack.some(v => v); + const shouldDiscard = ( ) => stack.some(v => v.known && v.discard); - const begif = (startDiscard, match) => { - if ( discard === false && startDiscard ) { - parts.push(match.index); + const begif = details => { + if ( discard === false && details.known && details.discard ) { + parts.push(details.pos); discard = true; } - stack.push(startDiscard); + stack.push(details); }; const endif = match => { @@ -4384,15 +4392,21 @@ export const utils = (( ) => { switch ( match[1] ) { case 'if': { - const startDiscard = this.evaluateExpr(match[2].trim(), env) === false; - begif(startDiscard, match); + const result = this.evaluateExpr(match[2].trim(), env); + begif({ + known: result !== undefined, + discard: result === false, + pos: match.index, + }); break; } case 'else': { if ( stack.length === 0 ) { break; } - const startDiscard = stack[stack.length-1] === false; + const details = stack[stack.length-1]; endif(match); - begif(startDiscard, match); + details.discard = details.discard === false; + details.pos = match.index; + begif(details); break; } case 'endif': { diff --git a/src/js/static-net-filtering.js b/src/js/static-net-filtering.js index 9a252fdce33cd..58b6570705c2d 100644 --- a/src/js/static-net-filtering.js +++ b/src/js/static-net-filtering.js @@ -19,28 +19,16 @@ Home: https://github.com/gorhill/uBlock */ -/* globals vAPI */ - -'use strict'; +import * as sfp from './static-filtering-parser.js'; -/******************************************************************************/ +import { domainFromHostname, hostnameFromNetworkURL } from './uri-utils.js'; +import { dropTask, queueTask } from './tasks.js'; -import { queueTask, dropTask } from './tasks.js'; import BidiTrieContainer from './biditrie.js'; -import HNTrieContainer from './hntrie.js'; import { CompiledListReader } from './static-filtering-io.js'; -import * as sfp from './static-filtering-parser.js'; - -import { - domainFromHostname, - hostnameFromNetworkURL, -} from './uri-utils.js'; - -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#browser_compatibility -// -// This import would be best done dynamically, but since dynamic imports are -// not supported by older browsers, for now a static import is necessary. import { FilteringContext } from './filtering-context.js'; +import HNTrieContainer from './hntrie.js'; +import { urlSkip } from './urlskip.js'; /******************************************************************************/ @@ -56,97 +44,99 @@ const keyvalStore = typeof vAPI !== 'undefined' /******************************************************************************/ -// 0fedcba9876543210 -// ||||||| | || | -// ||||||| | || | -// ||||||| | || | -// ||||||| | || | -// ||||||| | || +---- bit 0- 1: block=0, allow=1, block important=2 -// ||||||| | |+------ bit 2: unused -// ||||||| | +------- bit 3- 4: party [0-3] -// ||||||| +--------- bit 5- 9: type [0-31] -// ||||||+-------------- bit 10: headers-based filters -// |||||+--------------- bit 11: redirect filters -// ||||+---------------- bit 12: removeparam filters -// |||+----------------- bit 13: csp filters -// ||+------------------ bit 14: permissions filters -// |+------------------- bit 15: uritransform filters -// +-------------------- bit 16: replace filters -// TODO: bit 11-16 can be converted into 3-bit value, as these options are not +// 10fedcba9876543210 +// |||||||| | || | +// |||||||| | || | +// |||||||| | || | +// |||||||| | || | +// |||||||| | || +---- bit 0- 1: block=0, allow=1, block important=2 +// |||||||| | |+------ bit 2: unused +// |||||||| | +------- bit 3- 4: party [0-3] +// |||||||| +--------- bit 5- 9: type [0-31] +// |||||||+-------------- bit 10: headers-based filters +// ||||||+--------------- bit 11: redirect filters +// |||||+---------------- bit 12: removeparam filters +// ||||+----------------- bit 13: csp filters +// |||+------------------ bit 14: permissions filters +// ||+------------------- bit 15: uritransform filters +// |+-------------------- bit 16: replace filters +// +--------------------- bit 17: urlskip filters +// TODO: bit 11-17 could be converted into 3-bit value, as these options are not // meant to be combined. -const RealmBitsMask = 0b00000000111; -const ActionBitsMask = 0b00000000011; -const TypeBitsMask = 0b01111100000; -const TypeBitsOffset = 5; - -const BLOCK_REALM = 0b00000000000000000; -const ALLOW_REALM = 0b00000000000000001; -const IMPORTANT_REALM = 0b00000000000000010; +const BLOCK_REALM = 0b0000_0000_0000_0000_0000; +const ALLOW_REALM = 0b0000_0000_0000_0000_0001; +const IMPORTANT_REALM = 0b0000_0000_0000_0000_0010; +const BLOCKALLOW_REALM = BLOCK_REALM | ALLOW_REALM | IMPORTANT_REALM; const BLOCKIMPORTANT_REALM = BLOCK_REALM | IMPORTANT_REALM; -const ANYPARTY_REALM = 0b00000000000000000; -const FIRSTPARTY_REALM = 0b00000000000001000; -const THIRDPARTY_REALM = 0b00000000000010000; +const ANYPARTY_REALM = 0b0000_0000_0000_0000_0000; +const FIRSTPARTY_REALM = 0b0000_0000_0000_0000_1000; +const THIRDPARTY_REALM = 0b0000_0000_0000_0001_0000; const ALLPARTIES_REALM = FIRSTPARTY_REALM | THIRDPARTY_REALM; -const HEADERS_REALM = 0b00000010000000000; -const REDIRECT_REALM = 0b00000100000000000; -const REMOVEPARAM_REALM = 0b00001000000000000; -const CSP_REALM = 0b00010000000000000; -const PERMISSIONS_REALM = 0b00100000000000000; -const URLTRANSFORM_REALM = 0b01000000000000000; -const REPLACE_REALM = 0b10000000000000000; +const TYPE_REALM = 0b0000_0000_0011_1110_0000; +const HEADERS_REALM = 0b0000_0000_0100_0000_0000; +const REDIRECT_REALM = 0b0000_0000_1000_0000_0000; +const REMOVEPARAM_REALM = 0b0000_0001_0000_0000_0000; +const CSP_REALM = 0b0000_0010_0000_0000_0000; +const PERMISSIONS_REALM = 0b0000_0100_0000_0000_0000; +const URLTRANSFORM_REALM = 0b0000_1000_0000_0000_0000; +const REPLACE_REALM = 0b0001_0000_0000_0000_0000; +const URLSKIP_REALM = 0b0010_0000_0000_0000_0000; const MODIFY_REALMS = REDIRECT_REALM | CSP_REALM | REMOVEPARAM_REALM | PERMISSIONS_REALM | - URLTRANSFORM_REALM | REPLACE_REALM; + URLTRANSFORM_REALM | REPLACE_REALM | + URLSKIP_REALM; + +const TYPE_REALM_OFFSET = 5; const typeNameToTypeValue = { - 'no_type': 0 << TypeBitsOffset, - 'stylesheet': 1 << TypeBitsOffset, - 'image': 2 << TypeBitsOffset, - 'object': 3 << TypeBitsOffset, - 'object_subrequest': 3 << TypeBitsOffset, - 'script': 4 << TypeBitsOffset, - 'fetch': 5 << TypeBitsOffset, - 'xmlhttprequest': 5 << TypeBitsOffset, - 'sub_frame': 6 << TypeBitsOffset, - 'font': 7 << TypeBitsOffset, - 'media': 8 << TypeBitsOffset, - 'websocket': 9 << TypeBitsOffset, - 'beacon': 10 << TypeBitsOffset, - 'ping': 10 << TypeBitsOffset, - 'other': 11 << TypeBitsOffset, - 'popup': 12 << TypeBitsOffset, // start of behavioral filtering - 'popunder': 13 << TypeBitsOffset, - 'main_frame': 14 << TypeBitsOffset, // start of 1p behavioral filtering - 'generichide': 15 << TypeBitsOffset, - 'specifichide': 16 << TypeBitsOffset, - 'inline-font': 17 << TypeBitsOffset, - 'inline-script': 18 << TypeBitsOffset, - 'cname': 19 << TypeBitsOffset, - 'webrtc': 20 << TypeBitsOffset, - 'unsupported': 21 << TypeBitsOffset, + 'no_type': 0 << TYPE_REALM_OFFSET, + 'stylesheet': 1 << TYPE_REALM_OFFSET, + 'image': 2 << TYPE_REALM_OFFSET, + 'object': 3 << TYPE_REALM_OFFSET, + 'object_subrequest': 3 << TYPE_REALM_OFFSET, + 'script': 4 << TYPE_REALM_OFFSET, + 'fetch': 5 << TYPE_REALM_OFFSET, + 'xmlhttprequest': 5 << TYPE_REALM_OFFSET, + 'sub_frame': 6 << TYPE_REALM_OFFSET, + 'font': 7 << TYPE_REALM_OFFSET, + 'media': 8 << TYPE_REALM_OFFSET, + 'websocket': 9 << TYPE_REALM_OFFSET, + 'beacon': 10 << TYPE_REALM_OFFSET, + 'ping': 10 << TYPE_REALM_OFFSET, + 'other': 11 << TYPE_REALM_OFFSET, + 'popup': 12 << TYPE_REALM_OFFSET, // start of behavioral filtering + 'popunder': 13 << TYPE_REALM_OFFSET, + 'main_frame': 14 << TYPE_REALM_OFFSET, // start of 1p behavioral filtering + 'generichide': 15 << TYPE_REALM_OFFSET, + 'specifichide': 16 << TYPE_REALM_OFFSET, + 'inline-font': 17 << TYPE_REALM_OFFSET, + 'inline-script': 18 << TYPE_REALM_OFFSET, + 'cname': 19 << TYPE_REALM_OFFSET, + 'webrtc': 20 << TYPE_REALM_OFFSET, + 'unsupported': 21 << TYPE_REALM_OFFSET, }; const otherTypeBitValue = typeNameToTypeValue.other; const bitFromType = type => - 1 << ((typeNameToTypeValue[type] >>> TypeBitsOffset) - 1); + 1 << ((typeNameToTypeValue[type] >>> TYPE_REALM_OFFSET) - 1); // All network request types to bitmap -// bring origin to 0 (from TypeBitsOffset -- see typeNameToTypeValue) +// bring origin to 0 (from TYPE_REALM_OFFSET -- see typeNameToTypeValue) // left-shift 1 by the above-calculated value // subtract 1 to set all type bits const allNetworkTypesBits = - (1 << (otherTypeBitValue >>> TypeBitsOffset)) - 1; + (1 << (otherTypeBitValue >>> TYPE_REALM_OFFSET)) - 1; const allTypesBits = allNetworkTypesBits | - 1 << (typeNameToTypeValue['popup'] >>> TypeBitsOffset) - 1 | - 1 << (typeNameToTypeValue['main_frame'] >>> TypeBitsOffset) - 1 | - 1 << (typeNameToTypeValue['inline-font'] >>> TypeBitsOffset) - 1 | - 1 << (typeNameToTypeValue['inline-script'] >>> TypeBitsOffset) - 1; + 1 << (typeNameToTypeValue['popup'] >>> TYPE_REALM_OFFSET) - 1 | + 1 << (typeNameToTypeValue['main_frame'] >>> TYPE_REALM_OFFSET) - 1 | + 1 << (typeNameToTypeValue['inline-font'] >>> TYPE_REALM_OFFSET) - 1 | + 1 << (typeNameToTypeValue['inline-script'] >>> TYPE_REALM_OFFSET) - 1; const unsupportedTypeBit = - 1 << (typeNameToTypeValue['unsupported'] >>> TypeBitsOffset) - 1; + 1 << (typeNameToTypeValue['unsupported'] >>> TYPE_REALM_OFFSET) - 1; const typeValueToTypeName = [ '', @@ -199,6 +189,7 @@ const MODIFIER_TYPE_CSP = 4; const MODIFIER_TYPE_PERMISSIONS = 5; const MODIFIER_TYPE_URLTRANSFORM = 6; const MODIFIER_TYPE_REPLACE = 7; +const MODIFIER_TYPE_URLSKIP = 8; const modifierBitsFromType = new Map([ [ MODIFIER_TYPE_REDIRECT, REDIRECT_REALM ], @@ -208,6 +199,7 @@ const modifierBitsFromType = new Map([ [ MODIFIER_TYPE_PERMISSIONS, PERMISSIONS_REALM ], [ MODIFIER_TYPE_URLTRANSFORM, URLTRANSFORM_REALM ], [ MODIFIER_TYPE_REPLACE, REPLACE_REALM ], + [ MODIFIER_TYPE_URLSKIP, URLSKIP_REALM ], ]); const modifierTypeFromName = new Map([ @@ -218,6 +210,7 @@ const modifierTypeFromName = new Map([ [ 'permissions', MODIFIER_TYPE_PERMISSIONS ], [ 'uritransform', MODIFIER_TYPE_URLTRANSFORM ], [ 'replace', MODIFIER_TYPE_REPLACE ], + [ 'urlskip', MODIFIER_TYPE_URLSKIP ], ]); const modifierNameFromType = new Map([ @@ -228,22 +221,23 @@ const modifierNameFromType = new Map([ [ MODIFIER_TYPE_PERMISSIONS, 'permissions' ], [ MODIFIER_TYPE_URLTRANSFORM, 'uritransform' ], [ MODIFIER_TYPE_REPLACE, 'replace' ], + [ MODIFIER_TYPE_URLSKIP, 'urlskip' ], ]); -//const typeValueFromCatBits = catBits => (catBits >>> TypeBitsOffset) & 0b11111; +//const typeValueFromCatBits = catBits => (catBits >>> TYPE_REALM_OFFSET) & 0b11111; const MAX_TOKEN_LENGTH = 7; // Four upper bits of token hash are reserved for built-in predefined // token hashes, which should never end up being used when tokenizing // any arbitrary string. -const NO_TOKEN_HASH = 0x50000000; -const DOT_TOKEN_HASH = 0x10000000; -const ANY_TOKEN_HASH = 0x20000000; -const ANY_HTTPS_TOKEN_HASH = 0x30000000; -const ANY_HTTP_TOKEN_HASH = 0x40000000; -const EMPTY_TOKEN_HASH = 0xF0000000; -const INVALID_TOKEN_HASH = 0xFFFFFFFF; +const NO_TOKEN_HASH = 0x5000_0000; +const DOT_TOKEN_HASH = 0x1000_0000; +const ANY_TOKEN_HASH = 0x2000_0000; +const ANY_HTTPS_TOKEN_HASH = 0x3000_0000; +const ANY_HTTP_TOKEN_HASH = 0x4000_0000; +const EMPTY_TOKEN_HASH = 0xF000_0000; +const INVALID_TOKEN_HASH = 0xFFFF_FFFF; /******************************************************************************/ @@ -255,6 +249,7 @@ let $requestTypeValue = 0; let $requestURL = ''; let $requestURLRaw = ''; let $requestHostname = ''; +let $requestAddress = ''; let $docHostname = ''; let $docDomain = ''; let $tokenBeg = 0; @@ -386,9 +381,9 @@ class LogData { } else if ( (categoryBits & FIRSTPARTY_REALM) !== 0 ) { logData.options.unshift('1p'); } - const type = categoryBits & TypeBitsMask; + const type = categoryBits & TYPE_REALM; if ( type !== 0 ) { - logData.options.unshift(typeValueToTypeName[type >>> TypeBitsOffset]); + logData.options.unshift(typeValueToTypeName[type >>> TYPE_REALM_OFFSET]); } let raw = logData.pattern.join(''); if ( @@ -422,6 +417,14 @@ class LogData { isPureHostname() { return this.tokenHash === DOT_TOKEN_HASH; } + + static requote(s) { + if ( /^\$|^(["'`]).*\1$|,/.test(s) === false ) { return s; } + if ( s.includes("'") === false ) { return `'${s}'`; } + if ( s.includes('"') === false ) { return `"${s}"`; } + if ( s.includes('`') === false ) { return `\`${s}\``; } + return `'${s.replace(/'/g, "\\'")}'`; + } } /******************************************************************************/ @@ -707,6 +710,8 @@ const dnrAddRuleWarning = (rule, msg) => { FilterNotType FilterStrictParty FilterModifier + FilterOnHeaders + FilterIPAddress Collection: FilterCollection @@ -765,7 +770,7 @@ class FilterImportant { } static dnrFromCompiled(args, rule) { - rule.priority = (rule.priority || 1) + 10; + rule.priority = (rule.priority || 0) + 30; } static keyFromArgs() { @@ -1239,7 +1244,7 @@ class FilterRegex { return [ FilterRegex.fid, details.pattern, - details.patternMatchCase ? 1 : 0 + details.optionValues.has('match-case') ? 1 : 0, ]; } @@ -2080,7 +2085,7 @@ const compileToDomainOpt = (...args) => { class FilterDenyAllow extends FilterToDomainMissSet { static compile(details) { - return super.compile(details.denyallowOpt, 0b01); + return super.compile(details.optionValues.get('denyallow'), 0b01); } static logData(idata, details) { @@ -2141,7 +2146,7 @@ class FilterModifier { let opt = modifierNameFromType.get(filterData[idata+2]); const refs = filterRefs[filterData[idata+3]]; if ( refs.value !== '' ) { - opt += `=${refs.value}`; + opt += `=${LogData.requote(refs.value)}`; } details.options.push(opt); } @@ -2165,7 +2170,7 @@ class FilterModifierResult { this.refs = filterRefs[filterData[imodifierunit+3]]; this.ireportedunit = env.iunit; this.th = env.th; - this.bits = (env.bits & ~RealmBitsMask) | filterData[imodifierunit+1]; + this.bits = (env.bits & ~BLOCKALLOW_REALM) | filterData[imodifierunit+1]; } get result() { @@ -2907,7 +2912,7 @@ class FilterStrictParty { static dnrFromCompiled(args, rule) { const partyness = args[1] === 0 ? 1 : 3; - dnrAddRuleError(rule, `FilterStrictParty: Strict partyness strict${partyness}p not supported`); + dnrAddRuleError(rule, `strict${partyness}p not supported`); } static keyFromArgs(args) { @@ -2942,12 +2947,12 @@ class FilterOnHeaders { } static compile(details) { - return [ FilterOnHeaders.fid, details.headerOpt ]; + return [ FilterOnHeaders.fid, details.optionValues.get('header') ]; } static fromCompiled(args) { return filterDataAlloc( - args[0], // fid + args[0], // fid filterRefAdd({ headerOpt: args[1], $parsed: null, @@ -2955,12 +2960,16 @@ class FilterOnHeaders { ); } + static dnrFromCompiled(args, rule) { + dnrAddRuleError(rule, `header="${args[1]}" not supported`); + } + static logData(idata, details) { const irefs = filterData[idata+1]; const headerOpt = filterRefs[irefs].headerOpt; let opt = 'header'; if ( headerOpt !== '' ) { - opt += `=${headerOpt}`; + opt += `=${LogData.requote(headerOpt)}`; } details.options.push(opt); } @@ -2968,6 +2977,110 @@ class FilterOnHeaders { registerFilterClass(FilterOnHeaders); +/******************************************************************************/ + +class FilterIPAddress { + static TYPE_UNKNOWN = 0; + static TYPE_EQUAL = 1; + static TYPE_STARTSWITH = 2; + static TYPE_LAN = 3; + static TYPE_LOOPBACK = 4; + static TYPE_RE = 5; + static reIPv6IPv4lan = /^::ffff:(7f\w{2}|a\w{2}|a9fe|c0a8):\w+$/; + static reIPv6local = /^f[cd]\w{2}:/; + + static match(idata) { + const ipaddr = $requestAddress; + if ( ipaddr === '' ) { return false; } + const details = filterRefs[filterData[idata+1]]; + switch ( details.$type || this.TYPE_UNKNOWN ) { + case this.TYPE_LAN: + return this.isLAN(ipaddr); + case this.TYPE_LOOPBACK: + return this.isLoopback(ipaddr); + case this.TYPE_EQUAL: + case this.TYPE_STARTSWITH: + case this.TYPE_RE: + return details.$pattern.test(ipaddr); + default: + break; + } + const { pattern } = details; + if ( pattern === 'lan' ) { + details.$type = this.TYPE_LAN; + } else if ( pattern === 'loopback' ) { + details.$type = this.TYPE_LOOPBACK; + } else if ( pattern.startsWith('/') && pattern.endsWith('/') ) { + details.$type = this.TYPE_RE; + details.$pattern = new RegExp(pattern.slice(1, -1), 'm'); + } else if ( pattern.endsWith('*') ) { + details.$type = this.TYPE_STARTSWITH; + details.$pattern = new RegExp(`^${restrFromPlainPattern(pattern.slice(0, -1))}`, 'm'); + } else { + details.$type = this.TYPE_EQUAL; + details.$pattern = new RegExp(`^${restrFromPlainPattern(pattern)}$`, 'm'); + } + return this.match(idata); + } + + // https://github.com/uBlockOrigin/uAssets/blob/master/filters/lan-block.txt + // https://en.wikipedia.org/wiki/Reserved_IP_addresses + // `ipaddr` is assumed well-formed + static isLAN(ipaddr) { + const c0 = ipaddr.charCodeAt(0); + // ipv4 + if ( c0 === 0x30 /* 0 */ ) { + return ipaddr.startsWith('0.'); + } + if ( c0 === 0x31 /* 1 */ ) { + if ( ipaddr.startsWith('10.') ) { return true; } + if ( ipaddr.startsWith('127.') ) { return true; } + if ( ipaddr.startsWith('169.254.') ) { return true; } + if ( ipaddr.startsWith('172.') ) { + const v = parseInt(ipaddr.slice(4), 10); + return v >= 16 && v <= 31; + } + return ipaddr.startsWith('192.168.'); + } + // ipv6 + if ( c0 === 0x3A /* : */ ) { + if ( ipaddr.startsWith('::') === false ) { return false; } + if ( ipaddr === '::' || ipaddr === '::1' ) { return true; } + if ( ipaddr.startsWith('::ffff:') === false ) { return false; } + return this.reIPv6IPv4lan.test(ipaddr); + } + if ( c0 === 0x66 /* f */ ) { + return this.reIPv6local.test(ipaddr); + } + return false; + } + + static isLoopback(ipaddr) { + return ipaddr === '127.0.0.1' || ipaddr === '::1'; + } + + static compile(details) { + return [ FilterIPAddress.fid, details.optionValues.get('ipaddress') ]; + } + + static fromCompiled(args) { + const pattern = args[1]; + const details = { pattern }; + return filterDataAlloc(args[0], filterRefAdd(details)); + } + + static dnrFromCompiled(args, rule) { + dnrAddRuleError(rule, `"ipaddress=${args[1]}" not supported`); + } + + static logData(idata, details) { + const irefs = filterData[idata+1]; + details.options.push(`ipaddress=${LogData.requote(filterRefs[irefs].pattern)}`); + } +} + +registerFilterClass(FilterIPAddress); + /******************************************************************************/ /******************************************************************************/ @@ -3151,8 +3264,7 @@ class FilterCompiler { return Object.assign(this, other); } this.reToken = /[%0-9A-Za-z]+/g; - this.fromDomainOptList = []; - this.toDomainOptList = []; + this.optionValues = new Map(); this.tokenIdToNormalizedType = new Map([ [ sfp.NODE_TYPE_NET_OPTION_NAME_CNAME, bitFromType('cname') ], [ sfp.NODE_TYPE_NET_OPTION_NAME_CSS, bitFromType('stylesheet') ], @@ -3184,6 +3296,7 @@ class FilterCompiler { [ sfp.NODE_TYPE_NET_OPTION_NAME_REMOVEPARAM, MODIFIER_TYPE_REMOVEPARAM ], [ sfp.NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM, MODIFIER_TYPE_URLTRANSFORM ], [ sfp.NODE_TYPE_NET_OPTION_NAME_REPLACE, MODIFIER_TYPE_REPLACE ], + [ sfp.NODE_TYPE_NET_OPTION_NAME_URLSKIP, MODIFIER_TYPE_URLSKIP ], ]); // These top 100 "bad tokens" are collated using the "miss" histogram // from tokenHistograms(). The "score" is their occurrence among the @@ -3309,13 +3422,9 @@ class FilterCompiler { this.modifyType = undefined; this.modifyValue = undefined; this.pattern = ''; - this.patternMatchCase = false; this.party = ANYPARTY_REALM; this.optionUnitBits = 0; - this.fromDomainOpt = ''; - this.toDomainOpt = ''; - this.denyallowOpt = ''; - this.headerOpt = undefined; + this.optionValues.clear(); this.isPureHostname = false; this.isGeneric = false; this.isRegex = false; @@ -3327,8 +3436,6 @@ class FilterCompiler { this.notTypeBits = 0; this.methodBits = 0; this.notMethodBits = 0; - this.wildcardPos = -1; - this.caretPos = -1; return this; } @@ -3423,63 +3530,74 @@ class FilterCompiler { processOptionWithValue(parser, id) { switch ( id ) { - case sfp.NODE_TYPE_NET_OPTION_NAME_CSP: - if ( this.processCspOption(parser.getNetOptionValue(id)) === false ) { return false; } - break; - case sfp.NODE_TYPE_NET_OPTION_NAME_DENYALLOW: - this.denyallowOpt = this.processHostnameList( - parser.getNetFilterDenyallowOptionIterator(), - ); - if ( this.denyallowOpt === '' ) { return false; } - this.optionUnitBits |= DENYALLOW_BIT; - break; - case sfp.NODE_TYPE_NET_OPTION_NAME_FROM: - this.fromDomainOpt = this.processHostnameList( - parser.getNetFilterFromOptionIterator(), - this.fromDomainOptList - ); - if ( this.fromDomainOpt === '' ) { return false; } - this.optionUnitBits |= FROM_BIT; - break; - case sfp.NODE_TYPE_NET_OPTION_NAME_HEADER: { - this.headerOpt = parser.getNetOptionValue(id) || ''; - this.optionUnitBits |= HEADER_BIT; - break; + case sfp.NODE_TYPE_NET_OPTION_NAME_CSP: + if ( this.processCspOption(parser.getNetOptionValue(id)) === false ) { return false; } + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_DENYALLOW: { + const value = this.processHostnameList( + parser.getNetFilterDenyallowOptionIterator() + ); + if ( value === '' ) { return false; } + this.optionValues.set('denyallow', value); + this.optionUnitBits |= DENYALLOW_BIT; + break; + } + case sfp.NODE_TYPE_NET_OPTION_NAME_FROM: { + const iter = parser.getNetFilterFromOptionIterator(); + const list = []; + const value = this.processHostnameList(iter, list); + if ( value === '' ) { return false; } + this.optionValues.set('from', value); + this.optionValues.set('fromList', list); + this.optionUnitBits |= FROM_BIT; + break; + } + case sfp.NODE_TYPE_NET_OPTION_NAME_HEADER: { + this.optionValues.set('header', parser.getNetOptionValue(id) || ''); + this.optionUnitBits |= HEADER_BIT; + break; + } + case sfp.NODE_TYPE_NET_OPTION_NAME_IPADDRESS: + this.optionValues.set('ipaddress', parser.getNetOptionValue(id) || ''); + this.optionUnitBits |= IPADDRESS_BIT; + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_METHOD: + this.processMethodOption(parser.getNetOptionValue(id)); + this.optionUnitBits |= METHOD_BIT; + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_PERMISSIONS: + case sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE: + case sfp.NODE_TYPE_NET_OPTION_NAME_REMOVEPARAM: + case sfp.NODE_TYPE_NET_OPTION_NAME_REPLACE: + case sfp.NODE_TYPE_NET_OPTION_NAME_URLSKIP: + case sfp.NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM: + if ( this.processModifierOption(id, parser.getNetOptionValue(id)) === false ) { + return false; } - case sfp.NODE_TYPE_NET_OPTION_NAME_METHOD: - this.processMethodOption(parser.getNetOptionValue(id)); - this.optionUnitBits |= METHOD_BIT; - break; - case sfp.NODE_TYPE_NET_OPTION_NAME_PERMISSIONS: - case sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE: - case sfp.NODE_TYPE_NET_OPTION_NAME_REMOVEPARAM: - case sfp.NODE_TYPE_NET_OPTION_NAME_REPLACE: - case sfp.NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM: - if ( this.processModifierOption(id, parser.getNetOptionValue(id)) === false ) { - return false; - } - this.optionUnitBits |= MODIFY_BIT; - break; - case sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECT: { - const actualId = this.action === ALLOW_REALM - ? sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE - : id; - if ( this.processModifierOption(actualId, parser.getNetOptionValue(id)) === false ) { - return false; - } - this.optionUnitBits |= MODIFY_BIT; - break; + this.optionUnitBits |= MODIFY_BIT; + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECT: { + const actualId = this.action === ALLOW_REALM + ? sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE + : id; + if ( this.processModifierOption(actualId, parser.getNetOptionValue(id)) === false ) { + return false; } - case sfp.NODE_TYPE_NET_OPTION_NAME_TO: - this.toDomainOpt = this.processHostnameList( - parser.getNetFilterToOptionIterator(), - this.toDomainOptList - ); - if ( this.toDomainOpt === '' ) { return false; } - this.optionUnitBits |= TO_BIT; - break; - default: - break; + this.optionUnitBits |= MODIFY_BIT; + break; + } + case sfp.NODE_TYPE_NET_OPTION_NAME_TO: { + const iter = parser.getNetFilterToOptionIterator(); + const list = []; + const value = this.processHostnameList(iter, list); + if ( value === '' ) { return false; } + this.optionValues.set('to', value); + this.optionValues.set('toList', list); + this.optionUnitBits |= TO_BIT; + break; + } + default: + break; } return true; } @@ -3563,6 +3681,7 @@ class FilterCompiler { case sfp.NODE_TYPE_NET_OPTION_NAME_DENYALLOW: case sfp.NODE_TYPE_NET_OPTION_NAME_FROM: case sfp.NODE_TYPE_NET_OPTION_NAME_HEADER: + 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_REDIRECT: @@ -3570,6 +3689,7 @@ class FilterCompiler { case sfp.NODE_TYPE_NET_OPTION_NAME_REMOVEPARAM: case sfp.NODE_TYPE_NET_OPTION_NAME_REPLACE: case sfp.NODE_TYPE_NET_OPTION_NAME_TO: + case sfp.NODE_TYPE_NET_OPTION_NAME_URLSKIP: case sfp.NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM: if ( this.processOptionWithValue(parser, type) === false ) { return this.FILTER_INVALID; @@ -3596,7 +3716,7 @@ class FilterCompiler { this.action = BLOCKIMPORTANT_REALM; break; case sfp.NODE_TYPE_NET_OPTION_NAME_MATCHCASE: - this.patternMatchCase = true; + this.optionValues.set('match-case', true); break; case sfp.NODE_TYPE_NET_OPTION_NAME_MP4: { const id = this.action === ALLOW_REALM @@ -3666,11 +3786,6 @@ class FilterCompiler { return this.FILTER_OK; } - if ( this.isGeneric ) { - this.wildcardPos = this.pattern.indexOf('*'); - this.caretPos = this.pattern.indexOf('^'); - } - if ( this.pattern.length > 1024 ) { return this.FILTER_UNSUPPORTED; } @@ -3798,7 +3913,7 @@ class FilterCompiler { isJustOrigin() { if ( this.optionUnitBits !== FROM_BIT ) { return false; } if ( this.isRegex ) { return false; } - if ( /[\/~]/.test(this.fromDomainOpt) ) { return false; } + if ( /[/~]/.test(this.optionValues.get('from')) ) { return false; } if ( this.pattern === '*' ) { return true; } if ( this.anchor !== 0b010 ) { return false; } if ( /^(?:http[s*]?:(?:\/\/)?)$/.test(this.pattern) ) { return true; } @@ -3875,7 +3990,7 @@ class FilterCompiler { } else /* 'http:' */ { this.tokenHash = ANY_HTTP_TOKEN_HASH; } - for ( const hn of this.fromDomainOptList ) { + for ( const hn of this.optionValues.get('fromList') ) { this.compileToAtomicFilter(hn, writer); } return; @@ -3916,30 +4031,35 @@ class FilterCompiler { } // Origin - if ( this.fromDomainOpt !== '' ) { + if ( (this.optionUnitBits & FROM_BIT) !== 0 ) { compileFromDomainOpt( - this.fromDomainOptList, + this.optionValues.get('fromList'), units.length !== 0 && patternClass.isSlow === true, units ); } // Destination - if ( this.toDomainOpt !== '' ) { + if ( (this.optionUnitBits & TO_BIT) !== 0 ) { compileToDomainOpt( - this.toDomainOptList, + this.optionValues.get('toList'), units.length !== 0 && patternClass.isSlow === true, units ); } // Deny-allow - if ( this.denyallowOpt !== '' ) { + if ( (this.optionUnitBits & DENYALLOW_BIT) !== 0 ) { units.push(FilterDenyAllow.compile(this)); } + // IP address + if ( (this.optionUnitBits & IPADDRESS_BIT) !== 0 ) { + units.push(FilterIPAddress.compile(this)); + } + // Header - if ( this.headerOpt !== undefined ) { + if ( (this.optionUnitBits & HEADER_BIT) !== 0 ) { units.push(FilterOnHeaders.compile(this)); this.action |= HEADERS_REALM; } @@ -3957,16 +4077,21 @@ class FilterCompiler { // IMPORTANT: the modifier unit MUST always appear first in a sequence if ( this.modifyType !== undefined ) { units.unshift(FilterModifier.compile(this)); - this.action = (this.action & ~ActionBitsMask) | + this.action = (this.action & ~BLOCKALLOW_REALM) | modifierBitsFromType.get(this.modifyType); } - this.compileToAtomicFilter( - units.length === 1 - ? units[0] - : FilterCompositeAll.compile(units), - writer - ); + const fdata = units.length === 1 + ? units[0] + : FilterCompositeAll.compile(units); + + this.compileToAtomicFilter(fdata, writer); + + if ( (this.optionUnitBits & IPADDRESS_BIT) !== 0 ) { + if ( (this.action & HEADERS_REALM) !== 0 ) { return; } + this.action |= HEADERS_REALM; + this.compileToAtomicFilter(fdata, writer); + } } compilePattern(units) { @@ -3982,12 +4107,13 @@ class FilterCompiler { units.push(FilterPatternGeneric.compile(this)); return FilterPatternGeneric; } - if ( this.wildcardPos === -1 ) { - if ( this.caretPos === -1 ) { + if ( this.pattern.includes('*') === false ) { + const caretPos = this.pattern.indexOf('^'); + if ( caretPos === -1 ) { units.push(FilterPatternPlain.compile(this)); return FilterPatternPlain; } - if ( this.caretPos === (this.pattern.length - 1) ) { + if ( caretPos === (this.pattern.length - 1) ) { this.pattern = this.pattern.slice(0, -1); units.push(FilterPatternPlain.compile(this)); units.push(FilterTrailingSeparator.compile()); @@ -4020,7 +4146,7 @@ class FilterCompiler { do { if ( typeBits & 1 ) { writer.push([ - catBits | (bitOffset << TypeBitsOffset), + catBits | (bitOffset << TYPE_REALM_OFFSET), this.tokenHash, fdata ]); @@ -4032,15 +4158,16 @@ class FilterCompiler { } // These are to quickly test whether a filter is composite -const FROM_BIT = 0b000000001; -const TO_BIT = 0b000000010; -const DENYALLOW_BIT = 0b000000100; -const HEADER_BIT = 0b000001000; -const STRICT_PARTY_BIT = 0b000010000; -const MODIFY_BIT = 0b000100000; -const NOT_TYPE_BIT = 0b001000000; -const IMPORTANT_BIT = 0b010000000; -const METHOD_BIT = 0b100000000; +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; FilterCompiler.prototype.FILTER_OK = 0; FilterCompiler.prototype.FILTER_INVALID = 1; @@ -4182,7 +4309,7 @@ StaticNetFilteringEngine.prototype.freeze = function() { // the block-important realm should be checked when and only when // there is a matched exception filter, which important filters are // meant to override. - if ( (bits & ActionBitsMask) === BLOCKIMPORTANT_REALM ) { + if ( (bits & BLOCKALLOW_REALM) === BLOCKIMPORTANT_REALM ) { this.addFilterUnit( bits & ~IMPORTANT_REALM, tokenHash, @@ -4325,14 +4452,25 @@ StaticNetFilteringEngine.prototype.dnrFromCompiled = function(op, context, ...ar } } + // Priority: + // Removeparam: 1-4 + // Block: 10 (default priority) + // Redirect: 11-19 + // Excepted redirect: 21-29 + // Allow: 30 + // Block important: 40 + // Redirect important: 41-49 + const realms = new Map([ - [ BLOCK_REALM, 'block' ], - [ ALLOW_REALM, 'allow' ], - [ REDIRECT_REALM, 'redirect' ], - [ REMOVEPARAM_REALM, 'removeparam' ], - [ CSP_REALM, 'csp' ], - [ PERMISSIONS_REALM, 'permissions' ], - [ URLTRANSFORM_REALM, 'uritransform' ], + [ BLOCK_REALM, { type: 'block', priority: 10 } ], + [ ALLOW_REALM, { type: 'allow', priority: 30 } ], + [ 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 } ], + [ URLSKIP_REALM, { type: 'urlskip', priority: 0 } ], ]); const partyness = new Map([ [ ANYPARTY_REALM, '' ], @@ -4355,7 +4493,7 @@ StaticNetFilteringEngine.prototype.dnrFromCompiled = function(op, context, ...ar 'other', ]); const ruleset = []; - for ( const [ realmBits, realmName ] of realms ) { + for ( const [ realmBits, realmDetails ] of realms ) { for ( const [ partyBits, partyName ] of partyness ) { for ( const typeName in typeNameToTypeValue ) { if ( types.has(typeName) === false ) { continue; } @@ -4366,7 +4504,10 @@ StaticNetFilteringEngine.prototype.dnrFromCompiled = function(op, context, ...ar for ( const rules of bucket.values() ) { for ( const rule of rules ) { rule.action = rule.action || {}; - rule.action.type = realmName; + rule.action.type = realmDetails.type; + if ( realmDetails.priority !== 0 ) { + rule.priority = (rule.priority || 0) + realmDetails.priority; + } if ( partyName !== '' ) { rule.condition = rule.condition || {}; rule.condition.domainType = partyName; @@ -4462,12 +4603,11 @@ StaticNetFilteringEngine.prototype.dnrFromCompiled = function(op, context, ...ar } break; case 'redirect-rule': { - let priority = rule.priority || 1; let token = rule.__modifierValue; if ( token !== '' ) { const match = /:(\d+)$/.exec(token); if ( match !== null ) { - priority += parseInt(match[1], 10); + rule.priority += Math.min(rule.priority + parseInt(match[1], 10), 9); token = token.slice(0, match.index); } } @@ -4479,14 +4619,13 @@ StaticNetFilteringEngine.prototype.dnrFromCompiled = function(op, context, ...ar const extensionPath = resource || token; rule.action.type = 'redirect'; rule.action.redirect = { extensionPath }; - rule.priority = priority + 1; } else { rule.action.type = 'block'; - rule.priority = priority + 2; + rule.priority += 10; } break; } - case 'removeparam': + case 'removeparam': { rule.action.type = 'redirect'; if ( rule.__modifierValue === '|' ) { rule.__modifierValue = ''; @@ -4514,20 +4653,52 @@ StaticNetFilteringEngine.prototype.dnrFromCompiled = function(op, context, ...ar }; } if ( rule.condition.resourceTypes === undefined ) { - rule.condition.resourceTypes = [ - 'main_frame', - 'sub_frame', - 'xmlhttprequest', - ]; + if ( rule.condition.excludedResourceTypes === undefined ) { + rule.condition.resourceTypes = [ + 'main_frame', + 'sub_frame', + 'xmlhttprequest', + ]; + } + } + // https://github.com/uBlockOrigin/uBOL-home/issues/140 + // Mitigate until DNR API flaw is addressed by browser vendors + let priority = rule.priority || 1; + if ( rule.condition.urlFilter !== undefined ) { priority += 1; } + if ( rule.condition.regexFilter !== undefined ) { priority += 1; } + if ( rule.condition.initiatorDomains !== undefined ) { priority += 1; } + if ( rule.condition.requestDomains !== undefined ) { priority += 1; } + if ( priority !== 1 ) { + rule.priority = priority; } if ( rule.__modifierAction === ALLOW_REALM ) { dnrAddRuleError(rule, `Unsupported removeparam exception: ${rule.__modifierValue}`); } break; + } case 'uritransform': { dnrAddRuleError(rule, `Incompatible with DNR: uritransform=${rule.__modifierValue}`); break; } + case 'urlskip': { + let urlFilter = rule.condition?.urlFilter; + if ( urlFilter === undefined ) { break; } + let anchor = 0b000; + if ( urlFilter.startsWith('||') ) { + anchor |= 0b100; + urlFilter = urlFilter.slice(2); + } else if ( urlFilter.startsWith('|') ) { + anchor |= 0b10; + urlFilter = urlFilter.slice(1); + } + if ( urlFilter.endsWith('|') ) { + anchor |= 0b001; + urlFilter = urlFilter.slice(0, -1); + } + rule.condition.urlFilter = undefined; + rule.condition.regexFilter = restrFromGenericPattern(urlFilter, anchor); + break; + } default: dnrAddRuleError(rule, `Unsupported modifier ${rule.__modifierType}`); break; @@ -4649,20 +4820,13 @@ StaticNetFilteringEngine.prototype.toSelfie = function() { }; }; -StaticNetFilteringEngine.prototype.serialize = async function() { - const selfie = []; - const storage = { - put(name, data) { - selfie.push([ name, data ]); - } - }; - await this.toSelfie(storage, ''); - return JSON.stringify(selfie); +StaticNetFilteringEngine.prototype.serialize = function() { + return this.toSelfie(); }; /******************************************************************************/ -StaticNetFilteringEngine.prototype.fromSelfie = async function(selfie) { +StaticNetFilteringEngine.prototype.fromSelfie = function(selfie) { if ( typeof selfie !== 'object' || selfie === null ) { return; } this.reset(); @@ -4695,14 +4859,8 @@ StaticNetFilteringEngine.prototype.fromSelfie = async function(selfie) { return true; }; -StaticNetFilteringEngine.prototype.unserialize = async function(s) { - const selfie = new Map(JSON.parse(s)); - const storage = { - async get(name) { - return { content: selfie.get(name) }; - } - }; - return this.fromSelfie(storage, ''); +StaticNetFilteringEngine.prototype.unserialize = function(selfie) { + return this.fromSelfie(selfie); }; /******************************************************************************/ @@ -4746,7 +4904,8 @@ StaticNetFilteringEngine.prototype.matchAndFetchModifiers = function( $docDomain = fctxt.getDocDomain(); $requestHostname = fctxt.getHostname(); $requestMethodBit = fctxt.method || 0; - $requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset; + $requestTypeValue = (typeBits & TYPE_REALM) >>> TYPE_REALM_OFFSET; + $requestAddress = fctxt.getIPAddress(); const modifierType = modifierTypeFromName.get(modifierName); const modifierBits = modifierBitsFromType.get(modifierType); @@ -4840,7 +4999,7 @@ StaticNetFilteringEngine.prototype.matchAndFetchModifiers = function( const toRemove = new Map(); for ( const result of results ) { - const actionBits = result.bits & ActionBitsMask; + const actionBits = result.bits & BLOCKALLOW_REALM; const modifyValue = result.value; if ( actionBits === BLOCKIMPORTANT_REALM ) { toAddImportant.set(modifyValue, result); @@ -5043,7 +5202,8 @@ StaticNetFilteringEngine.prototype.matchRequestReverse = function(type, url) { $requestURL = urlTokenizer.setURL(url); $requestURLRaw = url; $requestMethodBit = 0; - $requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset; + $requestTypeValue = (typeBits & TYPE_REALM) >>> TYPE_REALM_OFFSET; + $requestAddress = ''; $isBlockImportant = false; this.$filterUnit = 0; @@ -5111,7 +5271,8 @@ StaticNetFilteringEngine.prototype.matchRequest = function(fctxt, modifiers = 0) $docDomain = fctxt.getDocDomain(); $requestHostname = fctxt.getHostname(); $requestMethodBit = fctxt.method || 0; - $requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset; + $requestTypeValue = (typeBits & TYPE_REALM) >>> TYPE_REALM_OFFSET; + $requestAddress = fctxt.getIPAddress(); $isBlockImportant = false; // Evaluate block realm before allow realm, and allow realm before @@ -5146,7 +5307,8 @@ StaticNetFilteringEngine.prototype.matchHeaders = function(fctxt, headers) { $docDomain = fctxt.getDocDomain(); $requestHostname = fctxt.getHostname(); $requestMethodBit = fctxt.method || 0; - $requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset; + $requestTypeValue = (typeBits & TYPE_REALM) >>> TYPE_REALM_OFFSET; + $requestAddress = fctxt.getIPAddress(); $httpHeaders.init(headers); let r = 0; @@ -5156,6 +5318,10 @@ StaticNetFilteringEngine.prototype.matchHeaders = function(fctxt, headers) { if ( r !== 0 && $isBlockImportant !== true ) { if ( this.realmMatchString(HEADERS_REALM | ALLOW_REALM, typeBits, partyBits) ) { r = 2; + } else if ( this.realmMatchString(ALLOW_REALM, typeBits, partyBits) ) { + r = 2; + } + if ( r === 2 ) { if ( this.realmMatchString(HEADERS_REALM | BLOCKIMPORTANT_REALM, typeBits, partyBits) ) { r = 1; } @@ -5187,22 +5353,44 @@ StaticNetFilteringEngine.prototype.redirectRequest = function(redirectEngine, fc return directives; }; -StaticNetFilteringEngine.prototype.transformRequest = function(fctxt) { +function parseRedirectRequestValue(directive) { + if ( directive.cache === null ) { + directive.cache = sfp.parseRedirectValue(directive.value); + } + return directive.cache; +} + +function compareRedirectRequests(redirectEngine, a, b) { + const { token: atok, priority: aint, bits: abits } = + parseRedirectRequestValue(a); + if ( redirectEngine.hasToken(atok) === false ) { return -1; } + const { token: btok, priority: bint, bits: bbits } = + parseRedirectRequestValue(b); + if ( redirectEngine.hasToken(btok) === false ) { return 1; } + if ( abits !== bbits ) { + if ( (abits & IMPORTANT_REALM) !== 0 ) { return 1; } + if ( (bbits & IMPORTANT_REALM) !== 0 ) { return -1; } + if ( (abits & ALLOW_REALM) !== 0 ) { return -1; } + if ( (bbits & ALLOW_REALM) !== 0 ) { return 1; } + } + return aint - bint; +} + +/******************************************************************************/ + +StaticNetFilteringEngine.prototype.transformRequest = function(fctxt, out = []) { const directives = this.matchAndFetchModifiers(fctxt, 'uritransform'); if ( directives === undefined ) { return; } const redirectURL = new URL(fctxt.url); - const out = []; for ( const directive of directives ) { if ( (directive.bits & ALLOW_REALM) !== 0 ) { out.push(directive); continue; } - const { refs } = directive; - if ( refs instanceof Object === false ) { continue; } - if ( refs.$cache === null ) { - refs.$cache = sfp.parseReplaceValue(refs.value); + if ( directive.cache === null ) { + directive.cache = sfp.parseReplaceValue(directive.value); } - const cache = refs.$cache; + const cache = directive.cache; if ( cache === undefined ) { continue; } const before = `${redirectURL.pathname}${redirectURL.search}${redirectURL.hash}`; if ( cache.re.test(before) !== true ) { continue; } @@ -5223,35 +5411,40 @@ StaticNetFilteringEngine.prototype.transformRequest = function(fctxt) { return out; }; -function parseRedirectRequestValue(directive) { - if ( directive.cache === null ) { - directive.cache = sfp.parseRedirectValue(directive.value); - } - return directive.cache; -} - -function compareRedirectRequests(redirectEngine, a, b) { - const { token: atok, priority: aint, bits: abits } = - parseRedirectRequestValue(a); - if ( redirectEngine.hasToken(atok) === false ) { return -1; } - const { token: btok, priority: bint, bits: bbits } = - parseRedirectRequestValue(b); - if ( redirectEngine.hasToken(btok) === false ) { return 1; } - if ( abits !== bbits ) { - if ( (abits & IMPORTANT_REALM) !== 0 ) { return 1; } - if ( (bbits & IMPORTANT_REALM) !== 0 ) { return -1; } - if ( (abits & ALLOW_REALM) !== 0 ) { return -1; } - if ( (bbits & ALLOW_REALM) !== 0 ) { return 1; } +StaticNetFilteringEngine.prototype.urlSkip = function( + fctxt, + blocked, + out = [] +) { + if ( fctxt.redirectURL !== undefined ) { return; } + const directives = this.matchAndFetchModifiers(fctxt, 'urlskip'); + if ( directives === undefined ) { return; } + for ( const directive of directives ) { + if ( (directive.bits & ALLOW_REALM) !== 0 ) { + out.push(directive); + continue; + } + const urlin = fctxt.url; + const value = directive.value; + const steps = value.includes(' ') && value.split(/ +/) || [ value ]; + const urlout = urlSkip(urlin, blocked, steps, directive); + if ( urlout === undefined ) { continue; } + if ( urlout === urlin ) { continue; } + fctxt.redirectURL = urlout; + out.push(directive); + break; } - return aint - bint; -} + if ( out.length === 0 ) { return; } + return out; +}; /******************************************************************************/ // https://github.com/uBlockOrigin/uBlock-issues/issues/1626 // Do not redirect when the number of query parameters does not change. -StaticNetFilteringEngine.prototype.filterQuery = function(fctxt) { +StaticNetFilteringEngine.prototype.filterQuery = function(fctxt, out = []) { + if ( fctxt.redirectURL !== undefined ) { return; } const directives = this.matchAndFetchModifiers(fctxt, 'removeparam'); if ( directives === undefined ) { return; } const url = fctxt.url; @@ -5274,7 +5467,6 @@ StaticNetFilteringEngine.prototype.filterQuery = function(fctxt) { } } const inParamCount = params.size; - const out = []; for ( const directive of directives ) { if ( params.size === 0 ) { break; } const isException = (directive.bits & ALLOW_REALM) !== 0; @@ -5384,17 +5576,76 @@ StaticNetFilteringEngine.prototype.enableWASM = function(wasmModuleFetcher, path /******************************************************************************/ -StaticNetFilteringEngine.prototype.test = async function(docURL, type, url) { +StaticNetFilteringEngine.prototype.test = function(details) { + const { url, type, from, redirectEngine } = details; + if ( url === undefined ) { return; } const fctxt = new FilteringContext(); - fctxt.setDocOriginFromURL(docURL); - fctxt.setType(type); fctxt.setURL(url); + fctxt.setType(type || ''); + fctxt.setDocOriginFromURL(from || ''); const r = this.matchRequest(fctxt); - console.info(`${r}`); + const out = [ `url: ${url}` ]; + if ( type ) { + out.push(`type: ${type}`); + } + if ( from ) { + out.push(`context: ${from}`); + } if ( r !== 0 ) { - console.info(this.toLogData()); + const logdata = this.toLogData(); + if ( r === 1 ) { + out.push(`blocked: ${logdata.raw}`); + } else if ( r === 2 ) { + out.push(`unblocked: ${logdata.raw}`); + } + } else { + out.push('not blocked'); } -}; + if ( r !== 1 ) { + const entries = this.transformRequest(fctxt); + if ( entries ) { + for ( const entry of entries ) { + out.push(`modified: ${entry.logData().raw}`); + } + } + if ( fctxt.redirectURL !== undefined && this.hasQuery(fctxt) ) { + const entries = this.filterQuery(fctxt, 'removeparam'); + if ( entries ) { + for ( const entry of entries ) { + out.push(`modified: ${entry.logData().raw}`); + } + } + } + if ( fctxt.type === 'main_frame' || fctxt.type === 'sub_frame' ) { + const csps = this.matchAndFetchModifiers(fctxt, 'csp'); + if ( csps ) { + for ( const csp of csps ) { + out.push(`modified: ${csp.logData().raw}`); + } + } + const pps = this.matchAndFetchModifiers(fctxt, 'permissions'); + if ( pps ) { + for ( const pp of pps ) { + out.push(`modified: ${pp.logData().raw}`); + } + } + } + } else if ( redirectEngine ) { + const redirects = this.redirectRequest(redirectEngine, fctxt); + if ( redirects ) { + for ( const redirect of redirects ) { + out.push(`modified: ${redirect.logData().raw}`); + } + } + } + const urlskips = this.matchAndFetchModifiers(fctxt, 'urlskip'); + if ( urlskips ) { + for ( const urlskip of urlskips ) { + out.push(`modified: ${urlskip.logData().raw}`); + } + } + return out.join('\n'); +} /******************************************************************************/ @@ -5489,6 +5740,7 @@ StaticNetFilteringEngine.prototype.dump = function() { [ PERMISSIONS_REALM, 'permissions' ], [ URLTRANSFORM_REALM, 'uritransform' ], [ REPLACE_REALM, 'replace' ], + [ URLSKIP_REALM, 'urlskip' ], ]); const partyness = new Map([ [ ANYPARTY_REALM, 'any-party' ], diff --git a/src/js/storage.js b/src/js/storage.js index dfd9695c3218f..c3b541bd3c159 100644 --- a/src/js/storage.js +++ b/src/js/storage.js @@ -319,7 +319,8 @@ onBroadcast(msg => { cnameIgnoreRootDocument: µbhs.cnameIgnoreRootDocument, cnameMaxTTL: µbhs.cnameMaxTTL, cnameReplayFullURL: µbhs.cnameReplayFullURL, - cnameUncloakProxied: µbhs.cnameUncloakProxied, + dnsCacheTTL: µbhs.dnsCacheTTL, + dnsResolveEnabled: µbhs.dnsResolveEnabled, }); }); @@ -607,6 +608,7 @@ onBroadcast(msg => { const url = new URL(options.docURL); comment = '! ' + this.hiddenSettings.autoCommentFilterTemplate + .replace('{{isodate}}', d.toISOString().split('T')[0]) .replace('{{date}}', d.toLocaleDateString(undefined, { dateStyle: 'medium' })) .replace('{{time}}', d.toLocaleTimeString()) .replace('{{hostname}}', url.hostname) @@ -1007,12 +1009,12 @@ onBroadcast(msg => { ubolog('loadFilterLists() Start'); t0 = Date.now(); loadedListKeys.length = 0; - loadingPromise = Promise.all([ - this.getAvailableLists().then(lists => onFilterListsReady(lists)), - this.loadRedirectResources().then(( ) => { - ubolog(`loadFilterLists() Redirects/scriptlets ready at ${elapsed()}`); - }), - ]).then(( ) => { + loadingPromise = this.loadRedirectResources().then(( ) => { + ubolog(`loadFilterLists() Redirects/scriptlets ready at ${elapsed()}`); + return this.getAvailableLists(); + }).then(lists => { + return onFilterListsReady(lists) + }).then(( ) => { onDone(); }); return loadingPromise; diff --git a/src/js/traffic.js b/src/js/traffic.js index f28f57fbbb366..df3b09714ff99 100644 --- a/src/js/traffic.js +++ b/src/js/traffic.js @@ -188,17 +188,21 @@ const onBeforeRootFrameRequest = function(fctxt) { } if ( logger.enabled ) { - fctxt.setFilter(logData); + fctxt.setRealm('network').setFilter(logData); } // https://github.com/uBlockOrigin/uBlock-issues/issues/760 // Redirect non-blocked request? - if ( result !== 1 && trusted === false && pageStore !== null ) { - pageStore.redirectNonBlockedRequest(fctxt); + if ( trusted === false && pageStore !== null ) { + if ( result !== 1 ) { + pageStore.redirectNonBlockedRequest(fctxt); + } else { + pageStore.skipMainDocument(fctxt, true); + } } if ( logger.enabled ) { - fctxt.setRealm('network').toLogger(); + fctxt.toLogger(); } // Redirected @@ -212,16 +216,20 @@ const onBeforeRootFrameRequest = function(fctxt) { if ( result !== 1 ) { return; } // No log data means no strict blocking (because we need to report why - // the blocking occurs. + // the blocking occurs if ( logData === undefined ) { return; } // Blocked + // Find out the URL navigated to should the document not be strict-blocked + pageStore.skipMainDocument(fctxt, false); + const query = encodeURIComponent(JSON.stringify({ url: requestURL, - hn: requestHostname, dn: fctxt.getDomain() || requestHostname, - fs: logData.raw + fs: logData.raw, + hn: requestHostname, + to: fctxt.redirectURL || '', })); vAPI.tabs.replace( @@ -485,7 +493,7 @@ const onHeadersReceived = function(details) { } if ( pageStore.getNetFilteringSwitch(fctxt) === false ) { return; } - if ( fctxt.itype === fctxt.IMAGE || fctxt.itype === fctxt.MEDIA ) { + if ( (fctxt.itype & foilLargeMediaElement.TYPE_BITS) !== 0 ) { const result = foilLargeMediaElement(details, fctxt, pageStore); if ( result !== undefined ) { return result; } } @@ -553,11 +561,16 @@ const onHeadersReceived = function(details) { if ( httpheaderFilteringEngine.apply(fctxt, responseHeaders) === true ) { modifiedHeaders = true; } - if ( injectCSP(fctxt, pageStore, responseHeaders) === true ) { - modifiedHeaders = true; - } - if ( injectPP(fctxt, pageStore, responseHeaders) === true ) { - modifiedHeaders = true; + + // https://github.com/uBlockOrigin/uBlock-issues/issues/229#issuecomment-2220354261 + // Inject CSP/PP in document resource only + if ( fctxt.isDocument() ) { + if ( injectCSP(fctxt, pageStore, responseHeaders) === true ) { + modifiedHeaders = true; + } + if ( injectPP(fctxt, pageStore, responseHeaders) === true ) { + modifiedHeaders = true; + } } // https://bugzilla.mozilla.org/show_bug.cgi?id=1376932 @@ -675,6 +688,7 @@ const bodyFilterer = (( ) => { const sessions = new Map(); const reContentTypeCharset = /charset=['"]?([^'" ]+)/i; const otherValidMimes = new Set([ + 'application/dash+xml', 'application/javascript', 'application/json', 'application/mpegurl', @@ -955,7 +969,7 @@ const injectCSP = function(fctxt, pageStore, responseHeaders) { const builtinDirectives = []; if ( pageStore.filterScripting(fctxt, true) === 1 ) { - builtinDirectives.push(µb.cspNoScripting); + builtinDirectives.push(µb.hiddenSettings.noScriptingCSP); if ( logger.enabled ) { fctxt.setRealm('network').setType('scripting').toLogger(); } @@ -1115,15 +1129,12 @@ const injectPP = function(fctxt, pageStore, responseHeaders) { const foilLargeMediaElement = function(details, fctxt, pageStore) { if ( details.fromCache === true ) { return; } - let size = 0; - if ( µb.userSettings.largeMediaSize !== 0 ) { - const headers = details.responseHeaders; - const i = headerIndexFromName('content-length', headers); - if ( i === -1 ) { return; } - size = parseInt(headers[i].value, 10) || 0; - } + onDemandHeaders.setHeaders(details.responseHeaders); + + const result = pageStore.filterLargeMediaElement(fctxt, onDemandHeaders); + + onDemandHeaders.reset(); - const result = pageStore.filterLargeMediaElement(fctxt, size); if ( result === 0 ) { return; } if ( logger.enabled ) { @@ -1133,16 +1144,15 @@ const foilLargeMediaElement = function(details, fctxt, pageStore) { return { cancel: true }; }; +foilLargeMediaElement.TYPE_BITS = fc.IMAGE | fc.MEDIA | fc.XMLHTTPREQUEST; + /******************************************************************************/ // Caller must ensure headerName is normalized to lower case. const headerIndexFromName = function(headerName, headers) { - let i = headers.length; - while ( i-- ) { - if ( headers[i].name.toLowerCase() === headerName ) { - return i; - } + for ( let i = 0, n = headers.length; i < n; i++ ) { + if ( headers[i].name.toLowerCase() === headerName ) { return i; } } return -1; }; @@ -1152,6 +1162,24 @@ const headerValueFromName = function(headerName, headers) { return i !== -1 ? headers[i].value : ''; }; +const onDemandHeaders = { + headers: [], + get contentLength() { + const contentLength = headerValueFromName('content-length', this.headers); + if ( contentLength === '' ) { return Number.NaN; } + return parseInt(contentLength, 10) || 0; + }, + get contentType() { + return headerValueFromName('content-type', this.headers); + }, + setHeaders(headers) { + this.headers = headers; + }, + reset() { + this.headers = []; + } +}; + /******************************************************************************/ const strictBlockBypasser = { diff --git a/src/js/urlskip.js b/src/js/urlskip.js new file mode 100644 index 0000000000000..e4182bbc4be24 --- /dev/null +++ b/src/js/urlskip.js @@ -0,0 +1,157 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient 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 +*/ + +const safeBase64Map = { '-': '+', '_': '/' }; +const safeBase64Replacer = s => safeBase64Map[s]; + +/** + * @trustedOption urlskip + * + * @description + * Extract a URL from another URL according to one or more transformation steps, + * thereby skipping over intermediate network request(s) to remote servers. + * Requires a trusted source. + * + * @param steps + * A serie of space-separated directives representing the transformation steps + * to perform to extract the final URL to which a network request should be + * redirected. + * + * Supported directives: + * + * `?name`: extract the value of parameter `name` as the current string. + * + * `&i`: extract the name of the parameter at position `i` as the current + * string. The position is 1-based. + * + * `/.../`: extract the first capture group of a regex as the current string. + * + * `+https`: prepend the current string with `https://`. + * + * `-base64`: decode the current string as a base64-encoded string. + * + * `-safebase64`: decode the current string as a safe base64-encoded string. + * + * `-uricomponent`: decode the current string as a URI encoded string. + * + * `-blocked`: allow the redirection of blocked requests. By default, blocked + * requests can't by urlskip'ed. + * + * At any given step, the currently extracted string may not necessarily be + * a valid URL, and more transformation steps may be needed to obtain a valid + * URL once all the steps are applied. + * + * An unsupported step or a failed step will abort the transformation and no + * redirection will be performed. + * + * The final step is expected to yield a valid URL. If the result is not a + * valid URL, no redirection will be performed. + * + * @example + * ||example.com/path/to/tracker$urlskip=?url + * ||example.com/path/to/tracker$urlskip=?url ?to + * ||pixiv.net/jump.php?$urlskip=&1 + * ||podtrac.com/pts/redirect.mp3/$urlskip=/\/redirect\.mp3\/(.*?\.mp3\b)/ +https + * + * */ + +export function urlSkip(url, blocked, steps, directive = {}) { + try { + let redirectBlocked = false; + let urlout = url; + for ( const step of steps ) { + const urlin = urlout; + const c0 = step.charCodeAt(0); + // Extract from URL parameter name at position i + if ( c0 === 0x26 ) { // & + const i = (parseInt(step.slice(1)) || 0) - 1; + if ( i < 0 ) { return; } + const url = new URL(urlin); + if ( i >= url.searchParams.size ) { return; } + const params = Array.from(url.searchParams.keys()); + urlout = decodeURIComponent(params[i]); + continue; + } + // Enforce https + if ( c0 === 0x2B && step === '+https' ) { + const s = urlin.replace(/^https?:\/\//, ''); + if ( /^[\w-]:\/\//.test(s) ) { return; } + urlout = `https://${s}`; + continue; + } + // Decode + if ( c0 === 0x2D ) { + // Base64 + if ( step === '-base64' ) { + urlout = self.atob(urlin); + continue; + } + // Safe Base64 + if ( step === '-safebase64' ) { + urlout = urlin.replace(/[-_]/g, safeBase64Replacer); + urlout = self.atob(urlout); + continue; + } + // URI component + if ( step === '-uricomponent' ) { + urlout = self.decodeURIComponent(urlin); + continue; + } + // Enable skip of blocked requests + if ( step === '-blocked' ) { + redirectBlocked = true; + continue; + } + } + // Regex extraction from first capture group + if ( c0 === 0x2F ) { // / + const re = directive.cache ?? new RegExp(step.slice(1, -1)); + if ( directive.cache === null ) { + directive.cache = re; + } + const match = re.exec(urlin); + if ( match === null ) { return; } + if ( match.length <= 1 ) { return; } + urlout = match[1]; + continue; + } + // Extract from URL parameter + if ( c0 === 0x3F ) { // ? + urlout = (new URL(urlin)).searchParams.get(step.slice(1)); + if ( urlout === null ) { return; } + if ( urlout.includes(' ') ) { + urlout = urlout.replace(/ /g, '%20'); + } + continue; + } + // Unknown directive + return; + } + 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) { + } +} diff --git a/src/logger-ui.html b/src/logger-ui.html index 9517968fde049..8836bd373de45 100644 --- a/src/logger-ui.html +++ b/src/logger-ui.html @@ -61,7 +61,7 @@ angle-up
-
+
css/fontimagemediascript
@@ -72,8 +72,7 @@
getheadpost
-
csppermissionsredirect
-
removeparamuritransform
+ csppermissionsredirectremoveparamreplaceurlskip
diff --git a/src/popup-fenix.html b/src/popup-fenix.html index 9abf3ddbab9a3..7c43e980ace09 100644 --- a/src/popup-fenix.html +++ b/src/popup-fenix.html @@ -16,7 +16,7 @@
-
­
+
­ 
lock diff --git a/src/support.html b/src/support.html index 12329423fecf2..fedb42ef2f470 100644 --- a/src/support.html +++ b/src/support.html @@ -93,6 +93,7 @@

+

diff --git a/src/web_accessible_resources/googlesyndication_adsbygoogle.js b/src/web_accessible_resources/googlesyndication_adsbygoogle.js index dec634bea57b3..294d054e51a23 100644 --- a/src/web_accessible_resources/googlesyndication_adsbygoogle.js +++ b/src/web_accessible_resources/googlesyndication_adsbygoogle.js @@ -38,7 +38,9 @@ const cfr = document.createElement('iframe'); cfr.id = `google_ads_frame${i}`; fr.appendChild(cfr); - phs[i].appendChild(fr); + const ph = phs[i]; + ph.appendChild(fr); + ph.setAttribute('data-adsbygoogle-status', 'done'); } }; if ( diff --git a/src/web_accessible_resources/noop-vast2.xml b/src/web_accessible_resources/noop-vast2.xml new file mode 100644 index 0000000000000..9bbe8d3cacde1 --- /dev/null +++ b/src/web_accessible_resources/noop-vast2.xml @@ -0,0 +1 @@ + diff --git a/src/web_accessible_resources/noop-vast3.xml b/src/web_accessible_resources/noop-vast3.xml new file mode 100644 index 0000000000000..cc1185f288234 --- /dev/null +++ b/src/web_accessible_resources/noop-vast3.xml @@ -0,0 +1 @@ + diff --git a/src/web_accessible_resources/noop-vast4.xml b/src/web_accessible_resources/noop-vast4.xml new file mode 100644 index 0000000000000..bd408f56bb932 --- /dev/null +++ b/src/web_accessible_resources/noop-vast4.xml @@ -0,0 +1 @@ + diff --git a/src/web_accessible_resources/noop-vmap1.0.xml b/src/web_accessible_resources/noop-vmap1.xml similarity index 100% rename from src/web_accessible_resources/noop-vmap1.0.xml rename to src/web_accessible_resources/noop-vmap1.xml diff --git a/tools/copy-common-files.sh b/tools/copy-common-files.sh index 56fb20ab3b8cf..29f7ee45c1e4d 100644 --- a/tools/copy-common-files.sh +++ b/tools/copy-common-files.sh @@ -12,6 +12,7 @@ cp -R src/css $DES/ cp -R src/img $DES/ mkdir $DES/js cp -R src/js/*.js $DES/js/ +cp -R src/js/resources $DES/js/ cp -R src/js/codemirror $DES/js/ cp -R src/js/scriptlets $DES/js/ cp -R src/js/wasm $DES/js/ diff --git a/tools/make-mv3.sh b/tools/make-mv3.sh index 13f82f4db33c5..5c812ec214dd5 100755 --- a/tools/make-mv3.sh +++ b/tools/make-mv3.sh @@ -76,6 +76,7 @@ cp "$UBO_DIR"/src/css/fa-icons.css "$DES"/css/ cp "$UBO_DIR"/src/js/dom.js "$DES"/js/ cp "$UBO_DIR"/src/js/fa-icons.js "$DES"/js/ cp "$UBO_DIR"/src/js/i18n.js "$DES"/js/ +cp "$UBO_DIR"/src/js/urlskip.js "$DES"/js/ cp "$UBO_DIR"/src/lib/punycode.js "$DES"/js/ cp -R "$UBO_DIR/src/img/flags-of-the-world" "$DES"/img @@ -107,9 +108,10 @@ if [ "$QUICK" != "yes" ]; then cp platform/mv3/package.json "$TMPDIR"/ cp platform/mv3/*.js "$TMPDIR"/ cp platform/mv3/*.mjs "$TMPDIR"/ + cp platform/mv3/*.html "$TMPDIR"/ cp platform/mv3/extension/js/utils.js "$TMPDIR"/js/ - cp "$UBO_DIR"/assets/assets.json "$TMPDIR"/ - cp "$UBO_DIR"/assets/resources/scriptlets.js "$TMPDIR"/ + cp -R "$UBO_DIR"/src/js/resources "$TMPDIR"/js/ + cp "$UBO_DIR"/assets/assets.dev.json "$TMPDIR"/ cp -R platform/mv3/scriptlets "$TMPDIR"/ mkdir -p "$TMPDIR"/web_accessible_resources cp "$UBO_DIR"/src/web_accessible_resources/* "$TMPDIR"/web_accessible_resources/ @@ -128,11 +130,19 @@ fi echo "*** uBOLite.mv3: extension ready" echo "Extension location: $DES/" -# Local build: use a different extension id than the official one -if [ -z "$TAGNAME" ] && [ "$PLATFORM" = "firefox" ]; then +# Local build +if [ -z "$TAGNAME" ]; then + # Enable DNR rule debugging tmp=$(mktemp) - jq '.browser_specific_settings.gecko.id = "uBOLite.dev@raymondhill.net"' "$DES/manifest.json" > "$tmp" \ + jq '.permissions += ["declarativeNetRequestFeedback"]' \ + "$DES/manifest.json" > "$tmp" \ && mv "$tmp" "$DES/manifest.json" + # Use a different extension id than the official one + if [ "$PLATFORM" = "firefox" ]; then + tmp=$(mktemp) + jq '.browser_specific_settings.gecko.id = "uBOLite.dev@raymondhill.net"' "$DES/manifest.json" > "$tmp" \ + && mv "$tmp" "$DES/manifest.json" + fi fi if [ "$FULL" = "yes" ]; then @@ -153,6 +163,7 @@ if [ "$FULL" = "yes" ]; then mkdir -p "$TMPDIR" cp -R "$DES"/* "$TMPDIR"/ cd "$TMPDIR" > /dev/null + rm -f ./log.txt zip "$PACKAGENAME" -qr ./* cd - > /dev/null cp "$TMPDIR"/"$PACKAGENAME" dist/build/ diff --git a/tools/make-nodejs.sh b/tools/make-nodejs.sh index 1e38ba1434043..ed8db6cbbf77a 100755 --- a/tools/make-nodejs.sh +++ b/tools/make-nodejs.sh @@ -7,6 +7,7 @@ set -e DES=$1 mkdir -p $DES/js +cp src/js/arglist-parser.js $DES/js cp src/js/base64-custom.js $DES/js cp src/js/biditrie.js $DES/js cp src/js/dynamic-net-filtering.js $DES/js @@ -14,12 +15,14 @@ cp src/js/filtering-context.js $DES/js cp src/js/hnswitches.js $DES/js cp src/js/hntrie.js $DES/js cp src/js/redirect-resources.js $DES/js +cp src/js/s14e-serializer.js $DES/js cp src/js/static-dnr-filtering.js $DES/js cp src/js/static-filtering-parser.js $DES/js cp src/js/static-net-filtering.js $DES/js cp src/js/static-filtering-io.js $DES/js cp src/js/tasks.js $DES/js cp src/js/text-utils.js $DES/js +cp src/js/urlskip.js $DES/js cp src/js/uri-utils.js $DES/js cp src/js/url-net-filtering.js $DES/js @@ -40,5 +43,4 @@ node -pe "JSON.stringify(Array.from(fs.readFileSync('src/lib/publicsuffixlist/wa > $DES/lib/publicsuffixlist/wasm/publicsuffixlist.wasm.json cp platform/nodejs/*.js $DES/ -cp platform/nodejs/README.md $DES/ cp LICENSE.txt $DES/ diff --git a/tools/make-npm.sh b/tools/make-npm.sh index 6bffadc735646..8a17b0e3c1e51 100755 --- a/tools/make-npm.sh +++ b/tools/make-npm.sh @@ -20,6 +20,7 @@ cp platform/npm/*.json $DES/ cp platform/npm/.*.json $DES/ cp platform/npm/*.js $DES/ cp -R platform/npm/tests $DES/ +cp platform/npm/README.md $DES/ cd $DES cd tests/data