diff --git a/.eslintrc.yml b/.eslintrc.yml deleted file mode 100644 index e9ff21ec0234c..0000000000000 --- a/.eslintrc.yml +++ /dev/null @@ -1,28 +0,0 @@ -env: - browser: true - es2022: true -extends: eslint:recommended -parserOptions: - sourceType: module -rules: - eqeqeq: - - warn - - always - indent: - - error - - 4 - - ignoredNodes: - - Program > IfStatement > BlockStatement - - Program > ExpressionStatement > CallExpression > ArrowFunctionExpression > BlockStatement - - Program > ExpressionStatement > CallExpression > FunctionExpression > BlockStatement - - CallExpression > MemberExpression - - ArrayExpression > * - - ObjectExpression > * - no-control-regex: off - no-empty: off - sort-imports: warn - strict: warn -globals: - browser: readonly - chrome: readonly - vAPI: readonly diff --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..90ebc5e554fb8 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,31 @@ 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 }} - 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 diff --git a/.gitignore b/.gitignore index dee00e98d3b96..0f4c6e0c4b582 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ *.bak *.pem +__pycache__/ +node_modules/ /dist/build/ /tmp/ +.DS_Store diff --git a/.gitmodules b/.gitmodules index e69de29bb2d1d..b81211f330b7a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "platform/mv3/extension/lib/codemirror/codemirror-ubol"] + path = platform/mv3/extension/lib/codemirror/codemirror-ubol + url = https://github.com/gorhill/codemirror-ubol.git diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 46c0d2e572cf2..0000000000000 --- a/.jshintrc +++ /dev/null @@ -1,22 +0,0 @@ -{ - "browser": true, - "devel": true, - "eqeqeq": true, - "esversion": 11, - "globals": { - "chrome": false, // global variable in Chromium, Chrome, Opera - "globalThis": false, - "self": false, - "vAPI": false, - "URLSearchParams": false, - "WebAssembly": false - }, - "laxbreak": true, - "newcap": false, - "nonew": false, - "strict": "global", - "sub": true, - "undef": true, - "unused": true, - "validthis": true -} diff --git a/CHANGELOG.md b/CHANGELOG.md index b7d8d3d6ba7b6..097165f1c5d75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,218 @@ +- [Improve `prevent-innerHTML` scriptlet](https://github.com/gorhill/uBlock/commit/b0396029bd) + +---------- + +# 1.65.0 + +## Fixes / changes + +- [Reset `important` option flag at `header` evaluation time](https://github.com/gorhill/uBlock/commit/66b68b4442) +- [Fix broken reverse lookup of filter lists](https://github.com/gorhill/uBlock/commit/527b4a201f) +- [Add `[trusted-]edit-inbound-object` scriptlets](https://github.com/gorhill/uBlock/commit/6e466cf945) +- [Improve `remove-cookie` scriptlet](https://github.com/gorhill/uBlock/commit/0a8ea58bb7) +- [Add `json-edit`-related scriptlets](https://github.com/gorhill/uBlock/commit/87e0434c90) +- [Improve `trusted-set-cookie` scriptlet](https://github.com/gorhill/uBlock/commit/3a2bb62519) +- [Force cache bypass reload when no-scripting switch is toggled](https://github.com/gorhill/uBlock/commit/4affe343dd) +- [Improve `jsonl[...]` suite of scriptlets](https://github.com/gorhill/uBlock/commit/ed9999efd6) +- [Add support for network filter option `message`](https://github.com/gorhill/uBlock/commit/d8298bb067) + - [Complete support for reporing strict-block messages](https://github.com/gorhill/uBlock/commit/253ef7ade3) +- [Make `header=` syntax compatible with DNR rules](https://github.com/gorhill/uBlock/commit/408b538e75) +- [Counter CodeMirror's `pointer-events: none` on scrollbars](https://github.com/gorhill/uBlock/commit/c44f043ed3) +- [Fix element picker issue with explicit dark theme](https://github.com/gorhill/uBlock/commit/0130fdf4a1) + +---------- + +# 1.64.0 + +## Fixes / changes + +- [Use custom blank page for embedded iframe in dashboard](https://github.com/gorhill/uBlock/commit/8cd6212867) +- [Use `color-scheme` `meta` tag, as suggested](https://github.com/gorhill/uBlock/commit/5c029b3532) +- [Bring zapper look in line with uBO Lite's zapper](https://github.com/gorhill/uBlock/commit/3f59f94b60) +- [Ignore `start_page` transition for popup-blocking purpose](https://github.com/gorhill/uBlock/commit/0243a141a7) +- [Exclude `chrome:` as valid openers for popup candidates](https://github.com/gorhill/uBlock/commit/59f4aca010) +- [Fetch diff patches from "reliable" servers only](https://github.com/gorhill/uBlock/commit/8b964a8c54) +- [Add `trusted-create-html` scriptlet](https://github.com/gorhill/uBlock/commit/20dd606504) +- [Mind potential race condition when dynamically registering scriptlets](https://github.com/gorhill/uBlock/commit/15e832da8a) +- [Fix undue unchecking of setting in "My filters"](https://github.com/gorhill/uBlock/commit/2bb6999e3f) +- [Add path support as target option in static extended filtering](https://github.com/gorhill/uBlock/commit/8b696a691a) +- [Add `trusted-prevent-fetch` scriptlet](https://github.com/gorhill/uBlock/commit/4ce26b63ff) +- [Code viewer shouldn't be maximizable](https://github.com/gorhill/uBlock/commit/97e740bd2c) +- [Add `json-edit` suite of scriptlets; extend `replace=` option](https://github.com/gorhill/uBlock/commit/b18daa53aa) +- [Improve `trusted-prevent-dom-bypass` scriptlet](https://github.com/gorhill/uBlock/commit/68a256bdde) +- [Add `jsonl-prune-xhr-response`/`jsonl-prune-fetch-response` scriptlets](https://github.com/gorhill/uBlock/commit/95a3be9d56) +- [Improve `[json-prune|trusted-replace]-fetch-response` scriptlets](https://github.com/gorhill/uBlock/commit/88fa550a96) + +---------- + +# 1.63.2 + +## Fixes / changes + +- [Fix TypedArray overflow](https://github.com/gorhill/uBlock/commit/76b80baaea) +- [Add prevent-innerHTML scriptlet](https://github.com/gorhill/uBlock/commit/fe744816f1) + +---------- + +# 1.63.0 + +## Fixes / changes + +- [Improve `prevent-set[Timeout|Interval]` scriptlets](https://github.com/gorhill/uBlock/commit/d36ea89a02) +- [Add quit button to element zapper mode](https://github.com/gorhill/uBlock/commit/4aebdbb0a9) +- [Improve `trusted-override-element-method` scriptlet](https://github.com/gorhill/uBlock/commit/9e946ce0c3) +- [Disable obsolete cache-control workaround for Firefox](https://github.com/gorhill/uBlock/commit/34cea70924) +- [Improve `overlay-buster` scriptlet](https://github.com/gorhill/uBlock/commit/fc231998b9) +- [Add ability to inject scriptlets according to origin of ancestor contexts](https://github.com/gorhill/uBlock/commit/a483f7955f) +- [Fix range parser in prevent-setTimeout scriptlet](https://github.com/gorhill/uBlock/commit/e636c32f2a) +- [Add filter option synonyms for `strict1p`/`strict3p`](https://github.com/gorhill/uBlock/commit/34df044808) +- [Increase URL buffer size to 8192 (from 2048)](https://github.com/gorhill/uBlock/commit/36404543e4) +- [Use onmessage/postMessage instead of BroadcastChannel in diff updater](https://github.com/gorhill/uBlock/commit/ea8853cda3) +- [Improve `disable-newtab-links` scriptlet](https://github.com/gorhill/uBlock/commit/d41989e62a) +- [Improve `prevent-addEventListener` scriptlet](https://github.com/gorhill/uBlock/commit/9c26a07b53) +- [Fix reverse lookup of `##^responseheader(...)` filters](https://github.com/gorhill/uBlock/commit/5921e50e03) +- [Improve `evaldata-prune` scriptlet](https://github.com/gorhill/uBlock/commit/9bb1a2baaf) +- [Comply with Mozilla's "User Consent and Control"](https://github.com/gorhill/uBlock/commit/344539d793) +- [Improve `noeval-if` scriptlet](https://github.com/gorhill/uBlock/commit/0df7faffac) +- [Add "closed","next", "mandatory", "agree/disagree" values to `set-cookie` scriptlet](https://github.com/gorhill/uBlock/commit/35a47d674b) (by @ryanbr) +- [Add `decline` value to `set-cookie` scriptlet](https://github.com/gorhill/uBlock/commit/4b12247da1) +- [Improve `abort-on-stack-trace` scriptlet](https://github.com/gorhill/uBlock/commit/b617926c1c) +- [Improve `href-sanitizer` scriptlet](https://github.com/gorhill/uBlock/commit/551c6bc6eb) + +---------- + +# 1.62.0 + +## Fixes / changes + +- [Fix deserialization of ArrayBuffer shared by multiple TypedArrays](https://github.com/gorhill/uBlock/commit/c92a518218) +- [Improve `trusted-suppress-native-method` scriptlet](https://github.com/gorhill/uBlock/commit/cb6c11ab6f) +- [Improve `urlskip=` filter option](https://github.com/gorhill/uBlock/commit/a7aa755f18) +- [Improve `parse-properties-to-match` scriptlet helper](https://github.com/gorhill/uBlock/commit/7494eaf621) +- [Improve `href-sanitizer` scriptlet](https://github.com/gorhill/uBlock/commit/9bf8d53ebe) +- [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..ddec8e4dca6bc 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,22 @@ # 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-chromium mv3-firefox mv3-edge mv3-safari ubol-codemirror \ compare maxcost medcost mincost modifiers record wasm -sources := $(wildcard assets/* assets/*/* dist/version src/* src/*/* src/*/*/* src/*/*/*/*) -platform := $(wildcard platform/* platform/*/* platform/*/*/* platform/*/*/*/* platform/*/*/*/*/*) +sources := ./dist/version $(shell find ./assets -type f) $(shell find ./src -type f) +platform := $(wildcard platform/*/*) assets := dist/build/uAssets +mv3-sources := \ + $(shell find ./src -type f) \ + $(wildcard platform/mv3/*) \ + $(shell find ./platform/mv3/extension -name codemirror-ubol -prune -o -type f) \ + platform/mv3/extension/lib/codemirror/codemirror-ubol/dist/cm6.bundle.ubol.min.js +mv3-data := $(shell find ./dist/build/mv3-data -type f) + +mv3-edge-deps := $(wildcard platform/mv3/edge/*) +mv3-safari-deps := $(wildcard platform/mv3/safari/*) all: chromium firefox npm @@ -31,11 +41,16 @@ firefox: dist/build/uBlock0.firefox dist/build/uBlock0.npm: tools/make-nodejs.sh $(sources) $(platform) $(assets) tools/make-npm.sh -# Build the Node.js package. npm: dist/build/uBlock0.npm -lint: npm - cd dist/build/uBlock0.npm && npm run lint +# Dev tools +node_modules: + npm install + +init: node_modules + +lint: init + npm run lint test: npm cd dist/build/uBlock0.npm && npm run test @@ -55,23 +70,37 @@ 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/mv3-data: + mkdir -p dist/build/mv3-data + +ubol-codemirror: + $(MAKE) -sC platform/mv3/extension/lib/codemirror/codemirror-ubol/ ubol.bundle + +dist/build/uBOLite.chromium: tools/make-mv3.sh $(mv3-sources) $(platform) $(mv3-data) dist/build/mv3-data tools/make-mv3.sh chromium -mv3-firefox: tools/make-mv3.sh $(sources) $(platform) +mv3-chromium: ubol-codemirror dist/build/uBOLite.chromium + +dist/build/uBOLite.firefox: tools/make-mv3.sh $(mv3-sources) $(platform) $(mv3-data) dist/build/mv3-data tools/make-mv3.sh firefox -mv3-quick: tools/make-mv3.sh $(sources) $(platform) - tools/make-mv3.sh quick +mv3-firefox: ubol-codemirror dist/build/uBOLite.firefox + +dist/build/uBOLite.edge: tools/make-mv3.sh $(mv3-sources) $(mv3-edge-deps) $(mv3-data) dist/build/mv3-data + tools/make-mv3.sh edge + +mv3-edge: ubol-codemirror dist/build/uBOLite.edge + +dist/build/uBOLite.safari: tools/make-mv3.sh $(mv3-sources) $(mv3-safari-deps) $(mv3-data) dist/build/mv3-data + tools/make-mv3.sh safari -mv3-full: tools/make-mv3.sh $(sources) $(platform) - tools/make-mv3.sh full +mv3-safari: ubol-codemirror dist/build/uBOLite.safari dist/build/uAssets: tools/pull-assets.sh clean: - rm -rf dist/build tmp/node_modules + rm -rf dist/build tmp/node_modules node_modules cleanassets: rm -rf dist/build/mv3-data dist/build/uAssets diff --git a/README.md b/README.md index 23e90367a14f8..9d6d2a50593f3 100644 --- a/README.md +++ b/README.md @@ -15,19 +15,14 @@ uBlock Origin (uBO) -

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

-*** - -

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

+| Browser | Install from ... | Status | +| :-------: | ---------------- | ------ | +| Get uBlock Origin for Firefox | Firefox Add-ons | [uBO works best on Firefox](https://github.com/gorhill/uBlock/wiki/uBlock-Origin-works-best-on-Firefox) | +| Get uBlock Origin for Microsoft Edge | Edge Add-ons | +| Get uBlock Origin for Opera | Opera Add-ons | +| Get uBlock Origin for Chromium | Chrome Web Store | About Google Chrome's "This extension may soon no longer be supported"
End of support on Chrome 139 | +| Get uBlock Origin for Thunderbird | Thunderbird Add-ons | [No longer updated and stuck at 1.49.2](https://github.com/uBlockOrigin/uBlock-issues/issues/2928) | *** @@ -99,7 +94,7 @@ In Thunderbird, uBlock Origin does not affect emails, just feeds. [Chrome Web Store][Chrome] -[Microsoft Edge Add-ons][Edge] (Published by: [Nicole Rolls][Nicole Rolls]) +[Microsoft Edge Add-ons][Edge] (Published by [Nicole Rolls][Nicole Rolls] until version 1.62. Ownership transfer at version 1.64.) [Opera Add-ons][Opera] @@ -142,16 +137,16 @@ If you ever want to contribute something, think about the people working hard to [Peter Lowe's Blocklist]: https://pgl.yoyo.org/adservers/ [Malicious Blocklist]: https://gitlab.com/malware-filter/urlhaus-filter#malicious-url-blocklist -[Performance]: https://www.debugbear.com/blog/chrome-extension-performance-2021#how-do-ad-blockers-and-privacy-tools-affect-browser-performance +[Performance]: https://www.debugbear.com/blog/chrome-extensions-website-performance#the-impact-of-ad-blocking-on-website-performance [EasyPrivacy]: https://easylist.to/#easyprivacy [Thunderbird]: https://addons.thunderbird.net/thunderbird/addon/ublock-origin/ -[Chrome Dev]: https://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 +156,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 +172,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 +182,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..328d4e75f307d 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 Gecko-based browsers, check out [why](https://github.com/gorhill/uBlock/wiki/uBlock-Origin-works-best-on-Firefox). + +- **Chromium**: Install directly from the [Chrome Web Store](https://chromewebstore.google.com/detail/ublock-origin-development/cgbcahbpdhpcegmbfconppldiemgcoii). -- **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..be85dd66a4f98 100644 --- a/assets/assets.dev.json +++ b/assets/assets.dev.json @@ -52,6 +52,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/filters.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/filters.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "ublock-badware": { @@ -71,6 +75,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/badware.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/badware.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets", "instructionURL": "https://github.com/gorhill/uBlock/wiki/Badware-risks" }, @@ -91,6 +99,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/privacy.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/privacy.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "ublock-unbreak": { @@ -109,6 +121,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/unbreak.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/unbreak.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "ublock-quick-fixes": { @@ -127,6 +143,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/quick-fixes.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/quick-fixes.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "adguard-generic": { @@ -136,8 +156,7 @@ "title": "AdGuard – Ads", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "adguard-mobile": { "content": "filters", @@ -147,8 +166,7 @@ "tags": "ads mobile", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "easylist": { "content": "filters", @@ -165,6 +183,10 @@ "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/thirdparties/easylist.txt", "https://ublockorigin.pages.dev/thirdparties/easylist.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://easylist.to/" }, "adguard-spyware-url": { @@ -174,8 +196,7 @@ "title": "AdGuard URL Tracking Protection", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "adguard-spyware": { "content": "filters", @@ -183,8 +204,7 @@ "off": true, "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "block-lan": { "content": "filters", @@ -216,6 +236,10 @@ "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/thirdparties/easyprivacy.txt", "https://ublockorigin.pages.dev/thirdparties/easyprivacy.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://easylist.to/" }, "urlhaus-1": { @@ -255,8 +279,7 @@ "title": "AdGuard – Cookie Notices", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "ublock-cookies-adguard": { "content": "filters", @@ -324,8 +347,7 @@ "title": "AdGuard – Social Widgets", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "fanboy-social": { "content": "filters", @@ -367,8 +389,7 @@ "title": "AdGuard – Popup Overlays", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "adguard-mobile-app-banners": { "content": "filters", @@ -378,8 +399,7 @@ "title": "AdGuard – Mobile App Banners", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "adguard-other-annoyances": { "content": "filters", @@ -389,8 +409,7 @@ "title": "AdGuard – Other Annoyances", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "adguard-widgets": { "content": "filters", @@ -400,8 +419,7 @@ "title": "AdGuard – Widgets", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "easylist-annoyances": { "content": "filters", @@ -488,6 +506,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/annoyances.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/annoyances.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "dpollock-0": { @@ -530,7 +552,7 @@ "off": true, "title": "🇪🇬eg 🇸🇦sa 🇲🇦ma 🇩🇿dz: Liste AR", "tags": "ads arabic اَلْعَرَبِيَّةُ‎", - "lang": "ar", + "lang": "ar kab", "contentURL": "https://easylist-downloads.adblockplus.org/Liste_AR.txt", "supportURL": "https://forums.lanik.us/viewforum.php?f=98" }, @@ -584,8 +606,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", @@ -603,7 +625,7 @@ "off": true, "title": "🇫🇷fr 🇨🇦ca: AdGuard Français", "tags": "ads french", - "lang": "ar br ff fr lb oc son", + "lang": "ar br ff fr kab lb oc son", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/16.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, @@ -622,9 +644,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 +660,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": { @@ -653,7 +679,7 @@ "off": true, "title": "🇮🇳in 🇱🇰lk 🇳🇵np: IndianList", "tags": "ads assamese bengali gujarati hindi kannada malayalam marathi nepali punjabi sinhala tamil telugu", - "lang": "as bn gu hi kn ml mr ne pa si ta te", + "lang": "as bn gu hi kn ml mr ne pa sat si ta te", "contentURL": "https://easylist-downloads.adblockplus.org/indianlist.txt", "supportURL": "https://github.com/mediumkreation/IndianList" }, @@ -681,8 +707,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", @@ -700,7 +726,7 @@ "off": true, "title": "🇮🇹it: EasyList Italy", "tags": "ads italian", - "lang": "it lij", + "lang": "fur it lij sc", "contentURL": "https://easylist-downloads.adblockplus.org/easylistitaly.txt", "supportURL": "https://forums.lanik.us/viewforum.php?f=96" }, @@ -712,8 +738,7 @@ "tags": "ads japanese 日本語", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "KOR-1": { "content": "filters", @@ -768,7 +793,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://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "NOR-0": { "content": "filters", @@ -778,9 +803,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" ], @@ -793,21 +816,20 @@ "off": true, "title": "🇵🇱pl: Oficjalne Polskie Filtry do uBlocka Origin", "tags": "ads polish polski", - "lang": "szl pl", + "lang": "szl pl _", "contentURL": "https://raw.githubusercontent.com/MajkiIT/polish-ads-filter/master/polish-adblock-filters/adblock.txt", - "supportURL": "https://github.com/MajkiIT/polish-ads-filter/issues", - "instructionURL": "https://github.com/MajkiIT/polish-ads-filter#polish-filters-for-adblock-ublock-origin--adguard" + "supportURL": "https://github.com/MajkiIT/polish-ads-filter" }, - "POL-2": { + "POL-3": { "content": "filters", "group": "regions", "parent": "🇵🇱pl: Oficjalne Polskie Filtry", "off": true, - "title": "🇵🇱pl: Oficjalne polskie filtry przeciwko alertom o Adblocku", - "tags": "ads polish polski", + "title": "🇵🇱pl: CERT.PL's Warning List", + "tags": "malware polish polski", "lang": "szl pl", - "contentURL": "https://raw.githubusercontent.com/olegwukr/polish-privacy-filters/master/anti-adblock.txt", - "supportURL": "https://github.com/olegwukr/polish-privacy-filters/issues" + "contentURL": "https://hole.cert.pl/domains/v2/domains_adblock.txt", + "supportURL": "https://cert.pl/lista-ostrzezen/" }, "ROU-1": { "content": "filters", @@ -824,10 +846,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", + "tags": "ads belarusian беларуская kazakh tatar russian русский ukrainian українська uzbek uk", + "lang": "be kk tt ru uz", "contentURL": "https://raw.githubusercontent.com/easylist/ruadlist/master/RuAdList-uBO.txt", "cdnURLs": [ "https://cdn.jsdelivr.net/gh/dimisa-RUAdList/RUAdListCDN@main/lists/ruadlist.ubo.min.txt", @@ -837,6 +860,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", @@ -855,8 +894,7 @@ "tags": "ads aragonese basque catalan spanish español galician guarani portuguese português", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "SVN-0": { "content": "filters", @@ -900,8 +938,17 @@ "tags": "ads turkish türkçe", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + "UKR-0": { + "content": "filters", + "group": "regions", + "off": true, + "title": "🇺🇦ua: AdGuard Ukrainian", + "tags": "ads ukraine україна", + "lang": "uk", + "contentURL": "https://filters.adtidy.org/extension/ublock/filters/23.txt", + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "VIE-1": { "content": "filters", diff --git a/assets/assets.json b/assets/assets.json index 44ccc1bad8fde..bfe125f671ea2 100644 --- a/assets/assets.json +++ b/assets/assets.json @@ -52,6 +52,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/filters.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/filters.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "ublock-badware": { @@ -71,6 +75,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/badware.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/badware.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets", "instructionURL": "https://github.com/gorhill/uBlock/wiki/Badware-risks" }, @@ -91,6 +99,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/privacy.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/privacy.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "ublock-unbreak": { @@ -109,6 +121,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/unbreak.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/unbreak.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "ublock-quick-fixes": { @@ -127,6 +143,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/quick-fixes.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/quick-fixes.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "adguard-generic": { @@ -136,8 +156,7 @@ "title": "AdGuard – Ads", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "adguard-mobile": { "content": "filters", @@ -147,8 +166,7 @@ "tags": "ads mobile", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "easylist": { "content": "filters", @@ -165,6 +183,10 @@ "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/thirdparties/easylist.txt", "https://ublockorigin.pages.dev/thirdparties/easylist.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://easylist.to/" }, "adguard-spyware-url": { @@ -174,8 +196,7 @@ "title": "AdGuard URL Tracking Protection", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "adguard-spyware": { "content": "filters", @@ -183,8 +204,7 @@ "off": true, "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "block-lan": { "content": "filters", @@ -216,6 +236,10 @@ "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/thirdparties/easyprivacy.txt", "https://ublockorigin.pages.dev/thirdparties/easyprivacy.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://easylist.to/" }, "urlhaus-1": { @@ -255,8 +279,7 @@ "title": "AdGuard – Cookie Notices", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "ublock-cookies-adguard": { "content": "filters", @@ -324,8 +347,7 @@ "title": "AdGuard – Social Widgets", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "fanboy-social": { "content": "filters", @@ -367,8 +389,7 @@ "title": "AdGuard – Popup Overlays", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "adguard-mobile-app-banners": { "content": "filters", @@ -378,8 +399,7 @@ "title": "AdGuard – Mobile App Banners", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "adguard-other-annoyances": { "content": "filters", @@ -389,8 +409,7 @@ "title": "AdGuard – Other Annoyances", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "adguard-widgets": { "content": "filters", @@ -400,8 +419,7 @@ "title": "AdGuard – Widgets", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "easylist-annoyances": { "content": "filters", @@ -488,6 +506,10 @@ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/annoyances.min.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/annoyances.min.txt" ], + "patchURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/", + "https://ublockorigin.pages.dev/filters/" + ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, "dpollock-0": { @@ -530,7 +552,7 @@ "off": true, "title": "🇪🇬eg 🇸🇦sa 🇲🇦ma 🇩🇿dz: Liste AR", "tags": "ads arabic اَلْعَرَبِيَّةُ‎", - "lang": "ar", + "lang": "ar kab", "contentURL": "https://easylist-downloads.adblockplus.org/Liste_AR.txt", "supportURL": "https://forums.lanik.us/viewforum.php?f=98" }, @@ -584,8 +606,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", @@ -603,7 +625,7 @@ "off": true, "title": "🇫🇷fr 🇨🇦ca: AdGuard Français", "tags": "ads french", - "lang": "ar br ff fr lb oc son", + "lang": "ar br ff fr kab lb oc son", "contentURL": "https://filters.adtidy.org/extension/ublock/filters/16.txt", "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, @@ -622,9 +644,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 +660,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": { @@ -653,7 +679,7 @@ "off": true, "title": "🇮🇳in 🇱🇰lk 🇳🇵np: IndianList", "tags": "ads assamese bengali gujarati hindi kannada malayalam marathi nepali punjabi sinhala tamil telugu", - "lang": "as bn gu hi kn ml mr ne pa si ta te", + "lang": "as bn gu hi kn ml mr ne pa sat si ta te", "contentURL": "https://easylist-downloads.adblockplus.org/indianlist.txt", "supportURL": "https://github.com/mediumkreation/IndianList" }, @@ -681,8 +707,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", @@ -700,7 +726,7 @@ "off": true, "title": "🇮🇹it: EasyList Italy", "tags": "ads italian", - "lang": "it lij", + "lang": "fur it lij sc", "contentURL": "https://easylist-downloads.adblockplus.org/easylistitaly.txt", "supportURL": "https://forums.lanik.us/viewforum.php?f=96" }, @@ -712,8 +738,7 @@ "tags": "ads japanese 日本語", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "KOR-1": { "content": "filters", @@ -768,7 +793,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://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "NOR-0": { "content": "filters", @@ -778,9 +803,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" ], @@ -793,21 +816,20 @@ "off": true, "title": "🇵🇱pl: Oficjalne Polskie Filtry do uBlocka Origin", "tags": "ads polish polski", - "lang": "szl pl", + "lang": "szl pl _", "contentURL": "https://raw.githubusercontent.com/MajkiIT/polish-ads-filter/master/polish-adblock-filters/adblock.txt", - "supportURL": "https://github.com/MajkiIT/polish-ads-filter/issues", - "instructionURL": "https://github.com/MajkiIT/polish-ads-filter#polish-filters-for-adblock-ublock-origin--adguard" + "supportURL": "https://github.com/MajkiIT/polish-ads-filter" }, - "POL-2": { + "POL-3": { "content": "filters", "group": "regions", "parent": "🇵🇱pl: Oficjalne Polskie Filtry", "off": true, - "title": "🇵🇱pl: Oficjalne polskie filtry przeciwko alertom o Adblocku", - "tags": "ads polish polski", + "title": "🇵🇱pl: CERT.PL's Warning List", + "tags": "malware polish polski", "lang": "szl pl", - "contentURL": "https://raw.githubusercontent.com/olegwukr/polish-privacy-filters/master/anti-adblock.txt", - "supportURL": "https://github.com/olegwukr/polish-privacy-filters/issues" + "contentURL": "https://hole.cert.pl/domains/v2/domains_adblock.txt", + "supportURL": "https://cert.pl/lista-ostrzezen/" }, "ROU-1": { "content": "filters", @@ -824,10 +846,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", + "tags": "ads belarusian беларуская kazakh tatar russian русский ukrainian українська uzbek uk", + "lang": "be kk tt ru uz", "contentURL": "https://raw.githubusercontent.com/easylist/ruadlist/master/RuAdList-uBO.txt", "cdnURLs": [ "https://cdn.jsdelivr.net/gh/dimisa-RUAdList/RUAdListCDN@main/lists/ruadlist.ubo.min.txt", @@ -837,6 +860,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", @@ -855,8 +894,7 @@ "tags": "ads aragonese basque catalan spanish español galician guarani portuguese português", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "SVN-0": { "content": "filters", @@ -900,8 +938,17 @@ "tags": "ads turkish türkçe", "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" + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + "UKR-0": { + "content": "filters", + "group": "regions", + "off": true, + "title": "🇺🇦ua: AdGuard Ukrainian", + "tags": "ads ukraine україна", + "lang": "uk", + "contentURL": "https://filters.adtidy.org/extension/ublock/filters/23.txt", + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" }, "VIE-1": { "content": "filters", diff --git a/assets/resources/scriptlets.js b/assets/resources/scriptlets.js deleted file mode 100644 index 54adfb623376a..0000000000000 --- a/assets/resources/scriptlets.js +++ /dev/null @@ -1,4811 +0,0 @@ -/******************************************************************************* - - 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 - - The scriptlets below are meant to be injected only into a - web page context. -*/ - -/* eslint no-prototype-builtins: 0 */ - -// Externally added to the private namespace in which scriptlets execute. -/* global scriptletGlobals */ - -export const builtinScriptlets = []; - -/******************************************************************************* - - Helper functions - - These are meant to be used as dependencies to injectable scriptlets. - -*******************************************************************************/ - -builtinScriptlets.push({ - name: 'safe-self.fn', - fn: safeSelf, -}); -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; -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'get-exception-token.fn', - fn: getExceptionToken, - dependencies: [ - 'safe-self.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 oe = self.onerror; - self.onerror = function(msg, ...args) { - if ( typeof msg === 'string' && msg.includes(token) ) { return true; } - if ( oe instanceof Function ) { - return oe.call(this, msg, ...args); - } - }.bind(); - return token; -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'should-debug.fn', - fn: shouldDebug, -}); -function shouldDebug(details) { - if ( details instanceof Object === false ) { return false; } - return scriptletGlobals.canDebug && details.debug; -} - -/******************************************************************************/ - -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 - -builtinScriptlets.push({ - name: 'generate-content.fn', - fn: generateContentFn, - dependencies: [ - 'safe-self.fn', - ], -}); -function generateContentFn(directive) { - const safe = safeSelf(); - const randomize = len => { - const chunks = []; - let textSize = 0; - do { - const s = safe.Math_random().toString(36).slice(2); - chunks.push(s); - textSize += s.length; - } - while ( textSize < len ); - return chunks.join(' ').slice(0, len); - }; - if ( directive === 'true' ) { - return Promise.resolve(randomize(10)); - } - if ( directive === 'emptyObj' ) { - return Promise.resolve('{}'); - } - if ( directive === 'emptyArr' ) { - return Promise.resolve('[]'); - } - if ( directive === 'emptyStr' ) { - return Promise.resolve(''); - } - 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 ) { - return new Promise(resolve => { - const warOrigin = scriptletGlobals.warOrigin; - const warName = directive.slice(4); - const fullpath = [ warOrigin, '/', warName ]; - const warSecret = scriptletGlobals.warSecret; - if ( warSecret !== undefined ) { - fullpath.push('?secret=', warSecret); - } - const warXHR = new safe.XMLHttpRequest(); - warXHR.responseType = 'text'; - warXHR.onloadend = ev => { - resolve(ev.target.responseText || ''); - }; - warXHR.open('GET', fullpath.join('')); - warXHR.send(); - }); - } - return Promise.resolve(''); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'abort-current-script-core.fn', - fn: abortCurrentScriptCore, - dependencies: [ - 'get-exception-token.fn', - 'safe-self.fn', - 'should-debug.fn', - ], -}); -// Issues to mind before changing anything: -// https://github.com/uBlockOrigin/uBlock-issues/issues/2154 -function abortCurrentScriptCore( - target = '', - needle = '', - context = '' -) { - if ( typeof target !== 'string' ) { return; } - if ( target === '' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('abort-current-script', target, needle, context); - const reNeedle = safe.patternToRegex(needle); - const reContext = safe.patternToRegex(context); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); - const thisScript = document.currentScript; - const chain = target.split('.'); - let owner = window; - let prop; - for (;;) { - prop = chain.shift(); - if ( chain.length === 0 ) { break; } - if ( prop in owner === false ) { break; } - owner = owner[prop]; - if ( owner instanceof Object === false ) { return; } - } - let value; - let desc = Object.getOwnPropertyDescriptor(owner, prop); - if ( - desc instanceof Object === false || - desc.get instanceof Function === false - ) { - value = owner[prop]; - desc = undefined; - } - const debug = shouldDebug(extraArgs); - const exceptionToken = getExceptionToken(); - const scriptTexts = new WeakMap(); - const getScriptText = elem => { - let text = elem.textContent; - if ( text.trim() !== '' ) { return text; } - if ( scriptTexts.has(elem) ) { return scriptTexts.get(elem); } - const [ , mime, content ] = - /^data:([^,]*),(.+)$/.exec(elem.src.trim()) || - [ '', '', '' ]; - try { - switch ( true ) { - case mime.endsWith(';base64'): - text = self.atob(content); - break; - default: - text = self.decodeURIComponent(content); - break; - } - } catch(ex) { - } - scriptTexts.set(elem, text); - return text; - }; - const validate = ( ) => { - const e = document.currentScript; - if ( e instanceof HTMLScriptElement === false ) { return; } - if ( e === thisScript ) { return; } - if ( context !== '' && reContext.test(e.src) === false ) { - // eslint-disable-next-line no-debugger - if ( debug === 'nomatch' || debug === 'all' ) { debugger; } - return; - } - if ( safe.logLevel > 1 && context !== '' ) { - safe.uboLog(logPrefix, `Matched src\n${e.src}`); - } - const scriptText = getScriptText(e); - if ( reNeedle.test(scriptText) === false ) { - // eslint-disable-next-line no-debugger - if ( debug === 'nomatch' || debug === 'all' ) { debugger; } - return; - } - if ( safe.logLevel > 1 ) { - safe.uboLog(logPrefix, `Matched text\n${scriptText}`); - } - // eslint-disable-next-line no-debugger - if ( debug === 'match' || debug === 'all' ) { debugger; } - safe.uboLog(logPrefix, 'Aborted'); - throw new ReferenceError(exceptionToken); - }; - // eslint-disable-next-line no-debugger - if ( debug === 'install' ) { debugger; } - try { - Object.defineProperty(owner, prop, { - get: function() { - validate(); - return desc instanceof Object - ? desc.get.call(owner) - : value; - }, - set: function(a) { - validate(); - if ( desc instanceof Object ) { - desc.set.call(owner, a); - } else { - value = a; - } - } - }); - } catch(ex) { - safe.uboErr(logPrefix, `Error: ${ex}`); - } -} - -/******************************************************************************/ - -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: [ - 'run-at.fn', - 'safe-self.fn', - ], -}); -function replaceNodeTextFn( - nodeName = '', - pattern = '', - replacement = '' -) { - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('replace-node-text.fn', ...Array.from(arguments)); - 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 stop = (takeRecord = true) => { - if ( takeRecord ) { - handleMutations(observer.takeRecords()); - } - observer.disconnect(); - if ( safe.logLevel > 1 ) { - safe.uboLog(logPrefix, 'Quitting'); - } - }; - 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; } - 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; - if ( safe.logLevel > 1 ) { - safe.uboLog(logPrefix, `Text before:\n${before.trim()}`); - } - safe.uboLog(logPrefix, `Text after:\n${after.trim()}`); - return sedCount === 0 || (sedCount -= 1) !== 0; - }; - const handleMutations = mutations => { - for ( const mutation of mutations ) { - for ( const node of mutation.addedNodes ) { - if ( reNodeName.test(node.nodeName) === false ) { continue; } - if ( handleNode(node) ) { continue; } - stop(false); return; - } - } - }; - const observer = new MutationObserver(handleMutations); - observer.observe(document, { childList: true, subtree: true }); - if ( document.documentElement ) { - const treeWalker = document.createTreeWalker( - document.documentElement, - NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT - ); - let count = 0; - for (;;) { - const node = treeWalker.nextNode(); - count += 1; - if ( node === null ) { break; } - if ( reNodeName.test(node.nodeName) === false ) { continue; } - if ( handleNode(node) ) { continue; } - stop(); break; - } - safe.uboLog(logPrefix, `${count} nodes present before installing mutation observer`); - } - if ( extraArgs.stay ) { return; } - runAt(( ) => { - const quitAfter = extraArgs.quitAfter || 0; - if ( quitAfter !== 0 ) { - setTimeout(( ) => { stop(); }, quitAfter); - } else { - stop(); - } - }, 'interactive'); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'object-prune.fn', - fn: objectPruneFn, - dependencies: [ - 'matches-stack-trace.fn', - 'object-find-owner.fn', - ], -}); -// When no "prune paths" argument is provided, the scriptlet is -// used for logging purpose and the "needle paths" argument is -// used to filter logging output. -// -// https://github.com/uBlockOrigin/uBlock-issues/issues/1545 -// - Add support for "remove everything if needle matches" case -function objectPruneFn( - obj, - rawPrunePaths, - rawNeedlePaths, - stackNeedleDetails = { matchAll: true }, - extraArgs = {} -) { - if ( typeof rawPrunePaths !== 'string' ) { return; } - const prunePaths = rawPrunePaths !== '' - ? rawPrunePaths.split(/ +/) - : []; - const needlePaths = prunePaths.length !== 0 && rawNeedlePaths !== '' - ? rawNeedlePaths.split(/ +/) - : []; - if ( stackNeedleDetails.matchAll !== true ) { - if ( matchesStackTrace(stackNeedleDetails, extraArgs.logstack) === false ) { - return; - } - } - if ( objectPruneFn.mustProcess === undefined ) { - objectPruneFn.mustProcess = (root, needlePaths) => { - for ( const needlePath of needlePaths ) { - if ( objectFindOwnerFn(root, needlePath) === false ) { - return false; - } - } - return true; - }; - } - if ( prunePaths.length === 0 ) { return; } - let outcome = 'nomatch'; - if ( objectPruneFn.mustProcess(obj, needlePaths) ) { - for ( const path of prunePaths ) { - if ( objectFindOwnerFn(obj, path, true) ) { - outcome = 'match'; - } - } - } - if ( outcome === 'match' ) { return obj; } -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'object-find-owner.fn', - fn: objectFindOwnerFn, -}); -function objectFindOwnerFn( - root, - path, - prune = false -) { - let owner = root; - let chain = path; - for (;;) { - if ( typeof owner !== 'object' || owner === null ) { return false; } - const pos = chain.indexOf('.'); - if ( pos === -1 ) { - if ( prune === false ) { - return owner.hasOwnProperty(chain); - } - let modified = false; - if ( chain === '*' ) { - for ( const key in owner ) { - if ( owner.hasOwnProperty(key) === false ) { continue; } - delete owner[key]; - modified = true; - } - } else if ( owner.hasOwnProperty(chain) ) { - delete owner[chain]; - modified = true; - } - return modified; - } - const prop = chain.slice(0, pos); - const next = chain.slice(pos + 1); - let found = false; - if ( prop === '[-]' && Array.isArray(owner) ) { - let i = owner.length; - while ( i-- ) { - if ( objectFindOwnerFn(owner[i], next) === false ) { continue; } - owner.splice(i, 1); - found = true; - } - return found; - } - if ( prop === '{-}' && owner instanceof Object ) { - for ( const key of Object.keys(owner) ) { - if ( objectFindOwnerFn(owner[key], next) === false ) { continue; } - delete owner[key]; - found = true; - } - return found; - } - if ( - prop === '[]' && Array.isArray(owner) || - prop === '{}' && owner instanceof Object || - prop === '*' && owner instanceof Object - ) { - for ( const key of Object.keys(owner) ) { - if (objectFindOwnerFn(owner[key], next, prune) === false ) { continue; } - found = true; - } - return found; - } - if ( owner.hasOwnProperty(prop) === false ) { return false; } - owner = owner[prop]; - chain = chain.slice(pos + 1); - } -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: '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, - dependencies: [ - 'get-exception-token.fn', - 'safe-self.fn', - ], -}); -function matchesStackTrace( - needleDetails, - logLevel = '' -) { - const safe = safeSelf(); - const exceptionToken = getExceptionToken(); - const error = new safe.Error(exceptionToken); - const docURL = new URL(self.location.href); - docURL.hash = ''; - // Normalize stack trace - const reLine = /(.*?@)?(\S+)(:\d+):\d+\)?$/; - const lines = []; - for ( let line of error.stack.split(/[\n\r]+/) ) { - if ( line.includes(exceptionToken) ) { continue; } - line = line.trim(); - const match = safe.RegExp_exec.call(reLine, line); - if ( match === null ) { continue; } - let url = match[2]; - if ( url.startsWith('(') ) { url = url.slice(1); } - if ( url === docURL.href ) { - url = 'inlineScript'; - } else if ( url.startsWith('') ) { - url = 'injectedScript'; - } - let fn = match[1] !== undefined - ? match[1].slice(0, -1) - : line.slice(0, match.index).trim(); - if ( fn.startsWith('at') ) { fn = fn.slice(2).trim(); } - let rowcol = match[3]; - lines.push(' ' + `${fn} ${url}${rowcol}:1`.trim()); - } - lines[0] = `stackDepth:${lines.length-1}`; - const stack = lines.join('\t'); - const r = needleDetails.matchAll !== true && - safe.testPattern(needleDetails, stack); - if ( - logLevel === 'all' || - logLevel === 'match' && r || - logLevel === 'nomatch' && !r - ) { - safe.uboLog(stack.replace(/\t/g, '\n')); - } - return r; -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'parse-properties-to-match.fn', - fn: parsePropertiesToMatch, - dependencies: [ - 'safe-self.fn', - ], -}); -function parsePropertiesToMatch(propsToMatch, implicit = '') { - const safe = safeSelf(); - const needles = new Map(); - if ( propsToMatch === undefined || propsToMatch === '' ) { return needles; } - const options = { canNegate: true }; - for ( const needle of propsToMatch.split(/\s+/) ) { - const [ prop, pattern ] = needle.split(':'); - if ( prop === '' ) { continue; } - if ( pattern !== undefined ) { - needles.set(prop, safe.initPattern(pattern, options)); - } else if ( implicit !== '' ) { - needles.set(implicit, safe.initPattern(prop, options)); - } - } - return needles; -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'match-object-properties.fn', - fn: matchObjectProperties, - dependencies: [ - 'safe-self.fn', - ], -}); -function matchObjectProperties(propNeedles, ...objs) { - if ( matchObjectProperties.extractProperties === undefined ) { - matchObjectProperties.extractProperties = (src, des, props) => { - for ( const p of props ) { - const v = src[p]; - if ( v === undefined ) { continue; } - des[p] = src[p]; - } - }; - } - const safe = safeSelf(); - const haystack = {}; - const props = safe.Array_from(propNeedles.keys()); - for ( const obj of objs ) { - if ( obj instanceof Object === false ) { continue; } - matchObjectProperties.extractProperties(obj, haystack, props); - } - for ( const [ prop, details ] of propNeedles ) { - let value = haystack[prop]; - if ( value === undefined ) { continue; } - if ( typeof value !== 'string' ) { - try { value = safe.JSON_stringify(value); } - catch(ex) { } - if ( typeof value !== 'string' ) { continue; } - } - if ( safe.testPattern(details, value) ) { continue; } - return false; - } - return true; -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'json-prune-fetch-response.fn', - fn: jsonPruneFetchResponseFn, - dependencies: [ - 'match-object-properties.fn', - 'object-prune.fn', - 'parse-properties-to-match.fn', - 'safe-self.fn', - ], -}); -function jsonPruneFetchResponseFn( - rawPrunePaths = '', - rawNeedlePaths = '' -) { - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('json-prune-fetch-response', rawPrunePaths, rawNeedlePaths); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); - const propNeedles = parsePropertiesToMatch(extraArgs.propsToMatch, 'url'); - const stackNeedle = safe.initPattern(extraArgs.stackToMatch || '', { canNegate: true }); - const logall = rawPrunePaths === ''; - const applyHandler = function(target, thisArg, args) { - const fetchPromise = Reflect.apply(target, thisArg, args); - let outcome = logall ? 'nomatch' : 'match'; - if ( propNeedles.size !== 0 ) { - const objs = [ args[0] instanceof Object ? args[0] : { url: args[0] } ]; - if ( objs[0] instanceof Request ) { - try { - objs[0] = safe.Request_clone.call(objs[0]); - } catch(ex) { - safe.uboErr(logPrefix, 'Error:', ex); - } - } - if ( args[1] instanceof Object ) { - objs.push(args[1]); - } - if ( matchObjectProperties(propNeedles, ...objs) === false ) { - outcome = 'nomatch'; - } - } - if ( logall === false && outcome === 'nomatch' ) { return fetchPromise; } - if ( safe.logLevel > 1 && outcome !== 'nomatch' && propNeedles.size !== 0 ) { - safe.uboLog(logPrefix, `Matched optional "propsToMatch"\n${extraArgs.propsToMatch}`); - } - return fetchPromise.then(responseBefore => { - const response = responseBefore.clone(); - return response.json().then(objBefore => { - if ( typeof objBefore !== 'object' ) { return responseBefore; } - if ( logall ) { - safe.uboLog(logPrefix, safe.JSON_stringify(objBefore, null, 2)); - return responseBefore; - } - const objAfter = objectPruneFn( - objBefore, - rawPrunePaths, - rawNeedlePaths, - stackNeedle, - extraArgs - ); - if ( typeof objAfter !== 'object' ) { return responseBefore; } - safe.uboLog(logPrefix, 'Pruned'); - const responseAfter = Response.json(objAfter, { - status: responseBefore.status, - statusText: responseBefore.statusText, - headers: responseBefore.headers, - }); - Object.defineProperties(responseAfter, { - ok: { value: responseBefore.ok }, - redirected: { value: responseBefore.redirected }, - type: { value: responseBefore.type }, - url: { value: responseBefore.url }, - }); - return responseAfter; - }).catch(reason => { - safe.uboErr(logPrefix, 'Error:', reason); - return responseBefore; - }); - }).catch(reason => { - safe.uboErr(logPrefix, 'Error:', reason); - return fetchPromise; - }); - }; - self.fetch = new Proxy(self.fetch, { - apply: applyHandler - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'replace-fetch-response.fn', - fn: replaceFetchResponseFn, - dependencies: [ - 'match-object-properties.fn', - 'parse-properties-to-match.fn', - 'safe-self.fn', - ], -}); -function replaceFetchResponseFn( - trusted = false, - pattern = '', - replacement = '', - propsToMatch = '' -) { - if ( trusted !== true ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('replace-fetch-response', pattern, replacement, propsToMatch); - if ( pattern === '*' ) { pattern = '.*'; } - const rePattern = safe.patternToRegex(pattern); - const propNeedles = parsePropertiesToMatch(propsToMatch, 'url'); - self.fetch = new Proxy(self.fetch, { - apply: function(target, thisArg, args) { - const fetchPromise = Reflect.apply(target, thisArg, args); - if ( pattern === '' ) { return fetchPromise; } - let outcome = 'match'; - if ( propNeedles.size !== 0 ) { - const objs = [ args[0] instanceof Object ? args[0] : { url: args[0] } ]; - if ( objs[0] instanceof Request ) { - try { - objs[0] = safe.Request_clone.call(objs[0]); - } - catch(ex) { - safe.uboErr(logPrefix, ex); - } - } - if ( args[1] instanceof Object ) { - objs.push(args[1]); - } - if ( matchObjectProperties(propNeedles, ...objs) === false ) { - outcome = 'nomatch'; - } - } - if ( outcome === 'nomatch' ) { return fetchPromise; } - if ( safe.logLevel > 1 ) { - safe.uboLog(logPrefix, `Matched "propsToMatch"\n${propsToMatch}`); - } - return fetchPromise.then(responseBefore => { - const response = responseBefore.clone(); - return response.text().then(textBefore => { - const textAfter = textBefore.replace(rePattern, replacement); - const outcome = textAfter !== textBefore ? 'match' : 'nomatch'; - if ( outcome === 'nomatch' ) { return responseBefore; } - safe.uboLog(logPrefix, 'Replaced'); - const responseAfter = new Response(textAfter, { - status: responseBefore.status, - statusText: responseBefore.statusText, - headers: responseBefore.headers, - }); - Object.defineProperties(responseAfter, { - ok: { value: responseBefore.ok }, - redirected: { value: responseBefore.redirected }, - type: { value: responseBefore.type }, - url: { value: responseBefore.url }, - }); - return responseAfter; - }).catch(reason => { - safe.uboErr(logPrefix, reason); - return responseBefore; - }); - }).catch(reason => { - safe.uboErr(logPrefix, reason); - return fetchPromise; - }); - } - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'proxy-apply.fn', - fn: proxyApplyFn, - dependencies: [ - 'safe-self.fn', - ], -}); -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 ( 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 - - These are meant to be used in the MAIN (webpage) execution world. - -*******************************************************************************/ - -builtinScriptlets.push({ - name: 'abort-current-script.js', - aliases: [ - 'acs.js', - 'abort-current-inline-script.js', - 'acis.js', - ], - fn: abortCurrentScript, - dependencies: [ - 'abort-current-script-core.fn', - 'run-at-html-element.fn', - ], -}); -// Issues to mind before changing anything: -// https://github.com/uBlockOrigin/uBlock-issues/issues/2154 -function abortCurrentScript(...args) { - runAtHtmlElementFn(( ) => { - abortCurrentScriptCore(...args); - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'abort-on-property-read.js', - aliases: [ - 'aopr.js', - ], - fn: abortOnPropertyRead, - dependencies: [ - 'get-exception-token.fn', - 'safe-self.fn', - ], -}); -function abortOnPropertyRead( - chain = '' -) { - if ( typeof chain !== 'string' ) { return; } - if ( chain === '' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('abort-on-property-read', chain); - const exceptionToken = getExceptionToken(); - const abort = function() { - safe.uboLog(logPrefix, 'Aborted'); - throw new ReferenceError(exceptionToken); - }; - const makeProxy = function(owner, chain) { - const pos = chain.indexOf('.'); - if ( pos === -1 ) { - const desc = Object.getOwnPropertyDescriptor(owner, chain); - if ( !desc || desc.get !== abort ) { - Object.defineProperty(owner, chain, { - get: abort, - set: function(){} - }); - } - return; - } - const prop = chain.slice(0, pos); - let v = owner[prop]; - chain = chain.slice(pos + 1); - if ( v ) { - makeProxy(v, chain); - return; - } - const desc = Object.getOwnPropertyDescriptor(owner, prop); - if ( desc && desc.set !== undefined ) { return; } - Object.defineProperty(owner, prop, { - get: function() { return v; }, - set: function(a) { - v = a; - if ( a instanceof Object ) { - makeProxy(a, chain); - } - } - }); - }; - const owner = window; - makeProxy(owner, chain); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'abort-on-property-write.js', - aliases: [ - 'aopw.js', - ], - fn: abortOnPropertyWrite, - dependencies: [ - 'get-exception-token.fn', - 'safe-self.fn', - ], -}); -function abortOnPropertyWrite( - prop = '' -) { - if ( typeof prop !== 'string' ) { return; } - if ( prop === '' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('abort-on-property-write', prop); - const exceptionToken = getExceptionToken(); - let owner = window; - for (;;) { - const pos = prop.indexOf('.'); - if ( pos === -1 ) { break; } - owner = owner[prop.slice(0, pos)]; - if ( owner instanceof Object === false ) { return; } - prop = prop.slice(pos + 1); - } - delete owner[prop]; - Object.defineProperty(owner, prop, { - set: function() { - safe.uboLog(logPrefix, 'Aborted'); - throw new ReferenceError(exceptionToken); - } - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'abort-on-stack-trace.js', - aliases: [ - 'aost.js', - ], - fn: abortOnStackTrace, - dependencies: [ - 'get-exception-token.fn', - 'matches-stack-trace.fn', - 'safe-self.fn', - ], -}); -function abortOnStackTrace( - chain = '', - needle = '' -) { - if ( typeof chain !== 'string' ) { return; } - const safe = safeSelf(); - const needleDetails = safe.initPattern(needle, { canNegate: true }); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); - if ( needle === '' ) { extraArgs.log = 'all'; } - const makeProxy = function(owner, chain) { - const pos = chain.indexOf('.'); - if ( pos === -1 ) { - let v = owner[chain]; - Object.defineProperty(owner, chain, { - get: function() { - if ( matchesStackTrace(needleDetails, extraArgs.log) ) { - throw new ReferenceError(getExceptionToken()); - } - return v; - }, - set: function(a) { - if ( matchesStackTrace(needleDetails, extraArgs.log) ) { - throw new ReferenceError(getExceptionToken()); - } - v = a; - }, - }); - return; - } - const prop = chain.slice(0, pos); - let v = owner[prop]; - chain = chain.slice(pos + 1); - if ( v ) { - makeProxy(v, chain); - return; - } - const desc = Object.getOwnPropertyDescriptor(owner, prop); - if ( desc && desc.set !== undefined ) { return; } - Object.defineProperty(owner, prop, { - get: function() { return v; }, - set: function(a) { - v = a; - if ( a instanceof Object ) { - makeProxy(a, chain); - } - } - }); - }; - const owner = window; - makeProxy(owner, chain); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'addEventListener-defuser.js', - aliases: [ - 'aeld.js', - 'prevent-addEventListener.js', - ], - fn: addEventListenerDefuser, - dependencies: [ - 'run-at.fn', - 'safe-self.fn', - 'should-debug.fn', - ], -}); -// https://github.com/uBlockOrigin/uAssets/issues/9123#issuecomment-848255120 -function addEventListenerDefuser( - type = '', - pattern = '' -) { - const safe = safeSelf(); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); - const logPrefix = safe.makeLogPrefix('prevent-addEventListener', type, pattern); - const reType = safe.patternToRegex(type, undefined, true); - const rePattern = safe.patternToRegex(pattern); - const debug = shouldDebug(extraArgs); - const targetSelector = extraArgs.elements || undefined; - const elementMatches = elem => { - if ( elem && elem.matches && elem.matches(targetSelector) ) { return true; } - const elems = Array.from(document.querySelectorAll(targetSelector)); - return elems.includes(elem); - }; - const elementDetails = elem => { - if ( elem instanceof Window ) { return 'window'; } - if ( elem instanceof Document ) { return 'document'; } - if ( elem instanceof Element === false ) { return '?'; } - const parts = []; - if ( elem.id !== '' ) { parts.push(`#${CSS.escape(elem.id)}`); } - for ( let i = 0; i < elem.classList.length; i++ ) { - parts.push(`.${CSS.escape(elem.classList.item(i))}`); - } - for ( let i = 0; i < elem.attributes.length; i++ ) { - const attr = elem.attributes.item(i); - if ( attr.name === 'id' ) { continue; } - if ( attr.name === 'class' ) { continue; } - parts.push(`[${CSS.escape(attr.name)}="${attr.value}"]`); - } - return parts.join(''); - }; - const shouldPrevent = (thisArg, type, handler) => { - const matchesType = safe.RegExp_test.call(reType, type); - const matchesHandler = safe.RegExp_test.call(rePattern, handler); - const matchesEither = matchesType || matchesHandler; - const matchesBoth = matchesType && matchesHandler; - if ( debug === 1 && matchesBoth || debug === 2 && matchesEither ) { - debugger; // eslint-disable-line no-debugger - } - if ( matchesBoth && targetSelector !== undefined ) { - if ( elementMatches(thisArg) === false ) { return false; } - } - 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]); - } - } 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); - } - return Reflect.get(target, prop, receiver); - }, - }; - self.EventTarget.prototype.addEventListener = new Proxy( - self.EventTarget.prototype.addEventListener, - eventListenerHandler - ); - }; - runAt(( ) => { - trapEddEventListeners(); - }, extraArgs.runAt); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'json-prune.js', - fn: jsonPrune, - dependencies: [ - 'object-prune.fn', - 'safe-self.fn', - ], -}); -function jsonPrune( - rawPrunePaths = '', - rawNeedlePaths = '', - stackNeedle = '' -) { - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('json-prune', rawPrunePaths, rawNeedlePaths, stackNeedle); - const stackNeedleDetails = safe.initPattern(stackNeedle, { canNegate: true }); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); - JSON.parse = new Proxy(JSON.parse, { - apply: function(target, thisArg, args) { - const objBefore = Reflect.apply(target, thisArg, args); - if ( rawPrunePaths === '' ) { - safe.uboLog(logPrefix, safe.JSON_stringify(objBefore, null, 2)); - } - const objAfter = objectPruneFn( - objBefore, - rawPrunePaths, - rawNeedlePaths, - stackNeedleDetails, - extraArgs - ); - if ( objAfter === undefined ) { return objBefore; } - safe.uboLog(logPrefix, 'Pruned'); - if ( safe.logLevel > 1 ) { - safe.uboLog(logPrefix, `After pruning:\n${safe.JSON_stringify(objAfter, null, 2)}`); - } - return objAfter; - }, - }); -} - -/******************************************************************************* - * - * json-prune-fetch-response.js - * - * Prune JSON response of fetch requests. - * - **/ - -builtinScriptlets.push({ - name: 'json-prune-fetch-response.js', - fn: jsonPruneFetchResponse, - dependencies: [ - 'json-prune-fetch-response.fn', - ], -}); -function jsonPruneFetchResponse(...args) { - jsonPruneFetchResponseFn(...args); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'json-prune-xhr-response.js', - fn: jsonPruneXhrResponse, - dependencies: [ - 'match-object-properties.fn', - 'object-prune.fn', - 'parse-properties-to-match.fn', - 'safe-self.fn', - ], -}); -function jsonPruneXhrResponse( - rawPrunePaths = '', - rawNeedlePaths = '' -) { - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('json-prune-xhr-response', rawPrunePaths, rawNeedlePaths); - const xhrInstances = new WeakMap(); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); - const propNeedles = parsePropertiesToMatch(extraArgs.propsToMatch, 'url'); - const stackNeedle = safe.initPattern(extraArgs.stackToMatch || '', { canNegate: true }); - self.XMLHttpRequest = class extends self.XMLHttpRequest { - open(method, url, ...args) { - const xhrDetails = { method, url }; - let outcome = 'match'; - if ( propNeedles.size !== 0 ) { - if ( matchObjectProperties(propNeedles, xhrDetails) === false ) { - outcome = 'nomatch'; - } - } - if ( outcome === 'match' ) { - if ( safe.logLevel > 1 ) { - safe.uboLog(logPrefix, `Matched optional "propsToMatch", "${extraArgs.propsToMatch}"`); - } - xhrInstances.set(this, xhrDetails); - } - return super.open(method, url, ...args); - } - get response() { - const innerResponse = super.response; - const xhrDetails = xhrInstances.get(this); - if ( xhrDetails === undefined ) { - return innerResponse; - } - const responseLength = typeof innerResponse === 'string' - ? innerResponse.length - : undefined; - if ( xhrDetails.lastResponseLength !== responseLength ) { - xhrDetails.response = undefined; - xhrDetails.lastResponseLength = responseLength; - } - if ( xhrDetails.response !== undefined ) { - return xhrDetails.response; - } - let objBefore; - if ( typeof innerResponse === 'object' ) { - objBefore = innerResponse; - } else if ( typeof innerResponse === 'string' ) { - try { - objBefore = safe.JSON_parse(innerResponse); - } catch(ex) { - } - } - if ( typeof objBefore !== 'object' ) { - return (xhrDetails.response = innerResponse); - } - const objAfter = objectPruneFn( - objBefore, - rawPrunePaths, - rawNeedlePaths, - stackNeedle, - extraArgs - ); - let outerResponse; - if ( typeof objAfter === 'object' ) { - outerResponse = typeof innerResponse === 'string' - ? safe.JSON_stringify(objAfter) - : objAfter; - safe.uboLog(logPrefix, 'Pruned'); - } else { - outerResponse = innerResponse; - } - return (xhrDetails.response = outerResponse); - } - get responseText() { - const response = this.response; - return typeof response !== 'string' - ? super.responseText - : response; - } - }; -} - -/******************************************************************************/ - -// There is still code out there which uses `eval` in lieu of `JSON.parse`. - -builtinScriptlets.push({ - name: 'evaldata-prune.js', - fn: evaldataPrune, - dependencies: [ - 'object-prune.fn', - ], -}); -function evaldataPrune( - rawPrunePaths = '', - rawNeedlePaths = '' -) { - self.eval = new Proxy(self.eval, { - apply(target, thisArg, args) { - const before = Reflect.apply(target, thisArg, args); - if ( typeof before === 'object' ) { - const after = objectPruneFn(before, rawPrunePaths, rawNeedlePaths); - return after || before; - } - return before; - } - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'adjust-setInterval.js', - aliases: [ - 'nano-setInterval-booster.js', - 'nano-sib.js', - ], - fn: adjustSetInterval, - dependencies: [ - 'safe-self.fn', - ], -}); -// Imported from: -// https://github.com/NanoAdblocker/NanoFilters/blob/1f3be7211bb0809c5106996f52564bf10c4525f7/NanoFiltersSource/NanoResources.txt#L126 -// -// Speed up or down setInterval, 3 optional arguments. -// The payload matcher, a string literal or a JavaScript RegExp, defaults -// to match all. -// delayMatcher -// The delay matcher, an integer, defaults to 1000. -// Use `*` to match any delay. -// boostRatio - The delay multiplier when there is a match, 0.5 speeds up by -// 2 times and 2 slows down by 2 times, defaults to 0.05 or speed up -// 20 times. Speed up and down both cap at 50 times. -function adjustSetInterval( - needleArg = '', - delayArg = '', - boostArg = '' -) { - if ( typeof needleArg !== 'string' ) { return; } - const safe = safeSelf(); - const reNeedle = safe.patternToRegex(needleArg); - let delay = delayArg !== '*' ? parseInt(delayArg, 10) : -1; - if ( isNaN(delay) || isFinite(delay) === false ) { delay = 1000; } - let boost = parseFloat(boostArg); - boost = isNaN(boost) === false && isFinite(boost) - ? Math.min(Math.max(boost, 0.001), 50) - : 0.05; - self.setInterval = new Proxy(self.setInterval, { - apply: function(target, thisArg, args) { - const [ a, b ] = args; - if ( - (delay === -1 || b === delay) && - reNeedle.test(a.toString()) - ) { - args[1] = b * boost; - } - return target.apply(thisArg, args); - } - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'adjust-setTimeout.js', - aliases: [ - 'nano-setTimeout-booster.js', - 'nano-stb.js', - ], - fn: adjustSetTimeout, - dependencies: [ - 'safe-self.fn', - ], -}); -// Imported from: -// https://github.com/NanoAdblocker/NanoFilters/blob/1f3be7211bb0809c5106996f52564bf10c4525f7/NanoFiltersSource/NanoResources.txt#L82 -// -// Speed up or down setTimeout, 3 optional arguments. -// funcMatcher -// The payload matcher, a string literal or a JavaScript RegExp, defaults -// to match all. -// delayMatcher -// The delay matcher, an integer, defaults to 1000. -// Use `*` to match any delay. -// boostRatio - The delay multiplier when there is a match, 0.5 speeds up by -// 2 times and 2 slows down by 2 times, defaults to 0.05 or speed up -// 20 times. Speed up and down both cap at 50 times. -function adjustSetTimeout( - needleArg = '', - delayArg = '', - boostArg = '' -) { - if ( typeof needleArg !== 'string' ) { return; } - const safe = safeSelf(); - const reNeedle = safe.patternToRegex(needleArg); - let delay = delayArg !== '*' ? parseInt(delayArg, 10) : -1; - if ( isNaN(delay) || isFinite(delay) === false ) { delay = 1000; } - let boost = parseFloat(boostArg); - boost = isNaN(boost) === false && isFinite(boost) - ? Math.min(Math.max(boost, 0.001), 50) - : 0.05; - self.setTimeout = new Proxy(self.setTimeout, { - apply: function(target, thisArg, args) { - const [ a, b ] = args; - if ( - (delay === -1 || b === delay) && - reNeedle.test(a.toString()) - ) { - args[1] = b * boost; - } - return target.apply(thisArg, args); - } - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'noeval-if.js', - aliases: [ - 'prevent-eval-if.js', - ], - fn: noEvalIf, - dependencies: [ - 'safe-self.fn', - ], -}); -function noEvalIf( - needle = '' -) { - if ( typeof needle !== 'string' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('noeval-if', needle); - const reNeedle = safe.patternToRegex(needle); - window.eval = new Proxy(window.eval, { // jshint ignore: line - apply: function(target, thisArg, args) { - const a = String(args[0]); - if ( needle !== '' && reNeedle.test(a) ) { - safe.uboLog(logPrefix, 'Prevented:\n', a); - return; - } - if ( needle === '' || safe.logLevel > 1 ) { - safe.uboLog(logPrefix, 'Not prevented:\n', a); - } - return Reflect.apply(target, thisArg, args); - } - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'prevent-fetch.js', - aliases: [ - 'no-fetch-if.js', - ], - fn: noFetchIf, - dependencies: [ - 'generate-content.fn', - 'safe-self.fn', - ], -}); -function noFetchIf( - propsToMatch = '', - responseBody = '' -) { - if ( typeof propsToMatch !== 'string' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('prevent-fetch', propsToMatch, responseBody); - const needles = []; - for ( const condition of propsToMatch.split(/\s+/) ) { - if ( condition === '' ) { continue; } - const pos = condition.indexOf(':'); - let key, value; - if ( pos !== -1 ) { - key = condition.slice(0, pos); - value = condition.slice(pos + 1); - } else { - key = 'url'; - value = condition; - } - needles.push({ key, re: safe.patternToRegex(value) }); - } - 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; - } - } - } catch(ex) { - } - if ( proceed ) { - return Reflect.apply(target, thisArg, args); - } - 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}`); - } - } - 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 - }); - } - return response; - }); - } - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'prevent-refresh.js', - aliases: [ - 'refresh-defuser.js', - ], - 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 = '' -) { - if ( typeof arg1 !== 'string' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('prevent-refresh', arg1); - 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; } - } - } - 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'); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'remove-class.js', - aliases: [ - 'rc.js', - ], - fn: removeClass, - world: 'ISOLATED', - dependencies: [ - 'run-at.fn', - 'safe-self.fn', - ], -}); -function removeClass( - rawToken = '', - rawSelector = '', - behavior = '' -) { - if ( typeof rawToken !== 'string' ) { return; } - if ( rawToken === '' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('remove-class', 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}`); - } - const mustStay = /\bstay\b/.test(behavior); - let timer; - const rmclass = ( ) => { - timer = undefined; - try { - const nodes = document.querySelectorAll(selector); - for ( const node of nodes ) { - node.classList.remove(...tokens); - safe.uboLog(logPrefix, 'Removed class(es)'); - } - } catch(ex) { - } - if ( mustStay ) { return; } - if ( document.readyState !== 'complete' ) { return; } - observer.disconnect(); - }; - 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; } - } - } - if ( skip ) { return; } - timer = safe.onIdle(rmclass, { timeout: 67 }); - }; - const observer = new MutationObserver(mutationHandler); - const start = ( ) => { - rmclass(); - observer.observe(document, { - attributes: true, - attributeFilter: [ 'class' ], - childList: true, - subtree: true, - }); - }; - runAt(( ) => { - start(); - }, /\bcomplete\b/.test(behavior) ? 'idle' : 'loading'); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'no-requestAnimationFrame-if.js', - aliases: [ - 'norafif.js', - 'prevent-requestAnimationFrame.js', - ], - fn: noRequestAnimationFrameIf, - dependencies: [ - 'safe-self.fn', - ], -}); -function noRequestAnimationFrameIf( - needle = '' -) { - if ( typeof needle !== '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; - } - 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; } - } - } - neuteredPeerConnections.add(instance); - return false; - }; - const peerConnectionCtor = window[rtcName]; - const peerConnectionProto = peerConnectionCtor.prototype; - peerConnectionProto.createDataChannel = - new Proxy(peerConnectionProto.createDataChannel, { - apply: function(target, thisArg, args) { - if ( isGoodConfig(target, args[1]) === false ) { - log('uBO:', args[1]); - return Reflect.apply(target, thisArg, args.slice(0, 1)); - } - return Reflect.apply(target, thisArg, args); - }, - }); - window[rtcName] = - new Proxy(peerConnectionCtor, { - construct: function(target, args) { - if ( isGoodConfig(target, args[0]) === false ) { - log('uBO:', args[0]); - return Reflect.construct(target); - } - return Reflect.construct(target, args); - } - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'no-xhr-if.js', - aliases: [ - 'prevent-xhr.js', - ], - fn: noXhrIf, - dependencies: [ - 'generate-content.fn', - 'match-object-properties.fn', - 'parse-properties-to-match.fn', - 'safe-self.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'); - } - }; -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'no-window-open-if.js', - aliases: [ - 'nowoif.js', - 'prevent-window-open.js', - 'window.open-defuser.js', - ], - fn: noWindowOpenIf, - dependencies: [ - 'safe-self.fn', - ], -}); -function noWindowOpenIf( - pattern = '', - delay = '', - decoy = '' -) { - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('no-window-open-if', pattern, delay, decoy); - const targetMatchResult = pattern.startsWith('!') === false; - if ( targetMatchResult === false ) { - pattern = pattern.slice(1); - } - const rePattern = safe.patternToRegex(pattern); - let autoRemoveAfter = parseInt(delay); - if ( isNaN(autoRemoveAfter) ) { - autoRemoveAfter = -1; - } - const createDecoy = function(tag, urlProp, url) { - const decoyElem = document.createElement(tag); - decoyElem[urlProp] = url; - decoyElem.style.setProperty('height','1px', 'important'); - decoyElem.style.setProperty('position','fixed', 'important'); - decoyElem.style.setProperty('top','-1px', 'important'); - decoyElem.style.setProperty('width','1px', 'important'); - document.body.appendChild(decoyElem); - setTimeout(( ) => { decoyElem.remove(); }, autoRemoveAfter * 1000); - 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); - }, - }); - } - return popup; - } - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'close-window.js', - aliases: [ - 'window-close-if.js', - ], - fn: closeWindow, - world: 'ISOLATED', - dependencies: [ - 'safe-self.fn', - ], -}); -// https://github.com/uBlockOrigin/uAssets/issues/10323#issuecomment-992312847 -// https://github.com/AdguardTeam/Scriptlets/issues/158 -// https://github.com/uBlockOrigin/uBlock-issues/discussions/2270 -function closeWindow( - arg1 = '' -) { - if ( typeof arg1 !== 'string' ) { return; } - const safe = safeSelf(); - let subject = ''; - if ( /^\/.*\/$/.test(arg1) ) { - subject = window.location.href; - } else if ( arg1 !== '' ) { - subject = `${window.location.pathname}${window.location.search}`; - } - try { - const re = safe.patternToRegex(arg1); - if ( re.test(subject) ) { - window.close(); - } - } catch(ex) { - console.log(ex); - } -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'window.name-defuser.js', - fn: windowNameDefuser, -}); -// https://github.com/gorhill/uBlock/issues/1228 -function windowNameDefuser() { - if ( window === window.top ) { - window.name = ''; - } -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'overlay-buster.js', - fn: overlayBuster, -}); -// Experimental: Generic nuisance overlay buster. -// if this works well and proves to be useful, this may end up -// as a stock tool in uBO's popup panel. -function overlayBuster() { - if ( window !== window.top ) { return; } - var tstart; - var ttl = 30000; - var delay = 0; - var delayStep = 50; - var buster = function() { - var docEl = document.documentElement, - bodyEl = document.body, - vw = Math.min(docEl.clientWidth, window.innerWidth), - vh = Math.min(docEl.clientHeight, window.innerHeight), - tol = Math.min(vw, vh) * 0.05, - el = document.elementFromPoint(vw/2, vh/2), - style, rect; - for (;;) { - if ( el === null || el.parentNode === null || el === bodyEl ) { - break; - } - style = window.getComputedStyle(el); - if ( parseInt(style.zIndex, 10) >= 1000 || style.position === 'fixed' ) { - rect = el.getBoundingClientRect(); - if ( rect.left <= tol && rect.top <= tol && (vw - rect.right) <= tol && (vh - rect.bottom) < tol ) { - el.parentNode.removeChild(el); - tstart = Date.now(); - el = document.elementFromPoint(vw/2, vh/2); - bodyEl.style.setProperty('overflow', 'auto', 'important'); - docEl.style.setProperty('overflow', 'auto', 'important'); - continue; - } - } - el = el.parentNode; - } - if ( (Date.now() - tstart) < ttl ) { - delay = Math.min(delay + delayStep, 1000); - setTimeout(buster, delay); - } - }; - var domReady = function(ev) { - if ( ev ) { - document.removeEventListener(ev.type, domReady); - } - tstart = Date.now(); - setTimeout(buster, delay); - }; - if ( document.readyState === 'loading' ) { - document.addEventListener('DOMContentLoaded', domReady); - } else { - domReady(); - } -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'alert-buster.js', - fn: alertBuster, -}); -// https://github.com/uBlockOrigin/uAssets/issues/8 -function alertBuster() { - window.alert = new Proxy(window.alert, { - apply: function(a) { - console.info(a); - }, - get(target, prop, receiver) { - if ( prop === 'toString' ) { - return target.toString.bind(target); - } - return Reflect.get(target, prop, receiver); - }, - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'nowebrtc.js', - fn: noWebrtc, -}); -// Prevent web pages from using RTCPeerConnection(), and report attempts in console. -function noWebrtc() { - var rtcName = window.RTCPeerConnection ? 'RTCPeerConnection' : ( - window.webkitRTCPeerConnection ? 'webkitRTCPeerConnection' : '' - ); - if ( rtcName === '' ) { return; } - var log = console.log.bind(console); - var pc = function(cfg) { - log('Document tried to create an RTCPeerConnection: %o', cfg); - }; - const noop = function() { - }; - pc.prototype = { - close: noop, - createDataChannel: noop, - createOffer: noop, - setRemoteDescription: noop, - toString: function() { - return '[object RTCPeerConnection]'; - } - }; - var z = window[rtcName]; - window[rtcName] = pc.bind(window); - if ( z.prototype ) { - z.prototype.createDataChannel = function() { - return { - close: function() {}, - send: function() {} - }; - }.bind(null); - } -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'disable-newtab-links.js', - fn: disableNewtabLinks, -}); -// https://github.com/uBlockOrigin/uAssets/issues/913 -function disableNewtabLinks() { - document.addEventListener('click', function(ev) { - var target = ev.target; - while ( target !== null ) { - if ( target.localName === 'a' && target.hasAttribute('target') ) { - ev.stopPropagation(); - ev.preventDefault(); - break; - } - target = target.parentNode; - } - }); -} - -/******************************************************************************/ - -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, - dependencies: [ - 'safe-self.fn', - ], -}); -function xmlPrune( - selector = '', - selectorCheck = '', - urlPattern = '' -) { - if ( typeof selector !== 'string' ) { return; } - if ( selector === '' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('xml-prune', selector, selectorCheck, urlPattern); - const reUrl = safe.patternToRegex(urlPattern); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); - const queryAll = (xmlDoc, selector) => { - const isXpath = /^xpath\(.+\)$/.test(selector); - if ( isXpath === false ) { - return Array.from(xmlDoc.querySelectorAll(selector)); - } - const xpr = xmlDoc.evaluate( - selector.slice(6, -1), - xmlDoc, - null, - XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, - null - ); - const out = []; - for ( let i = 0; i < xpr.snapshotLength; i++ ) { - const node = xpr.snapshotItem(i); - out.push(node); - } - return out; - }; - const pruneFromDoc = xmlDoc => { - try { - if ( selectorCheck !== '' && xmlDoc.querySelector(selectorCheck) === null ) { - return xmlDoc; - } - if ( extraArgs.logdoc ) { - const serializer = new XMLSerializer(); - safe.uboLog(logPrefix, `Document is\n\t${serializer.serializeToString(xmlDoc)}`); - } - const items = queryAll(xmlDoc, selector); - if ( items.length === 0 ) { return xmlDoc; } - safe.uboLog(logPrefix, `Removing ${items.length} items`); - for ( const item of items ) { - if ( item.nodeType === 1 ) { - item.remove(); - } else if ( item.nodeType === 2 ) { - item.ownerElement.removeAttribute(item.nodeName); - } - safe.uboLog(logPrefix, `${item.constructor.name}.${item.nodeName} removed`); - } - } catch(ex) { - safe.uboErr(logPrefix, `Error: ${ex}`); - } - return xmlDoc; - }; - const pruneFromText = text => { - if ( (/^\s*\s*$/.test(text)) === false ) { - return text; - } - try { - const xmlParser = new DOMParser(); - const xmlDoc = xmlParser.parseFromString(text, 'text/xml'); - pruneFromDoc(xmlDoc); - const serializer = new XMLSerializer(); - text = serializer.serializeToString(xmlDoc); - } catch(ex) { - } - return text; - }; - const urlFromArg = arg => { - if ( typeof arg === 'string' ) { return arg; } - if ( arg instanceof Request ) { return arg.url; } - return String(arg); - }; - self.fetch = new Proxy(self.fetch, { - apply: function(target, thisArg, args) { - const fetchPromise = Reflect.apply(target, thisArg, args); - if ( reUrl.test(urlFromArg(args[0])) === false ) { - return fetchPromise; - } - return fetchPromise.then(responseBefore => { - const response = responseBefore.clone(); - return response.text().then(text => { - const responseAfter = new Response(pruneFromText(text), { - status: responseBefore.status, - statusText: responseBefore.statusText, - headers: responseBefore.headers, - }); - Object.defineProperties(responseAfter, { - ok: { value: responseBefore.ok }, - redirected: { value: responseBefore.redirected }, - type: { value: responseBefore.type }, - url: { value: responseBefore.url }, - }); - return responseAfter; - }).catch(( ) => - responseBefore - ); - }); - } - }); - self.XMLHttpRequest.prototype.open = new Proxy(self.XMLHttpRequest.prototype.open, { - apply: async (target, thisArg, args) => { - if ( reUrl.test(urlFromArg(args[1])) === false ) { - return Reflect.apply(target, thisArg, args); - } - thisArg.addEventListener('readystatechange', function() { - if ( thisArg.readyState !== 4 ) { return; } - const type = thisArg.responseType; - if ( - type === 'document' || - type === '' && thisArg.responseXML instanceof XMLDocument - ) { - pruneFromDoc(thisArg.responseXML); - const serializer = new XMLSerializer(); - const textout = serializer.serializeToString(thisArg.responseXML); - Object.defineProperty(thisArg, 'responseText', { value: textout }); - return; - } - if ( - type === 'text' || - type === '' && typeof thisArg.responseText === 'string' - ) { - const textin = thisArg.responseText; - const textout = pruneFromText(textin); - if ( textout === textin ) { return; } - Object.defineProperty(thisArg, 'response', { value: textout }); - Object.defineProperty(thisArg, 'responseText', { value: textout }); - return; - } - }); - return Reflect.apply(target, thisArg, args); - } - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'm3u-prune.js', - fn: m3uPrune, - dependencies: [ - 'safe-self.fn', - ], -}); -// https://en.wikipedia.org/wiki/M3U -function m3uPrune( - m3uPattern = '', - urlPattern = '' -) { - if ( typeof m3uPattern !== 'string' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('m3u-prune', m3uPattern, urlPattern); - const toLog = []; - const regexFromArg = arg => { - if ( arg === '' ) { return /^/; } - const match = /^\/(.+)\/([gms]*)$/.exec(arg); - if ( match !== null ) { - let flags = match[2] || ''; - if ( flags.includes('m') ) { flags += 's'; } - return new RegExp(match[1], flags); - } - return new RegExp( - arg.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*+/g, '.*?') - ); - }; - const reM3u = regexFromArg(m3uPattern); - const reUrl = regexFromArg(urlPattern); - const pruneSpliceoutBlock = (lines, i) => { - if ( lines[i].startsWith('#EXT-X-CUE:TYPE="SpliceOut"') === false ) { - return false; - } - toLog.push(`\t${lines[i]}`); - lines[i] = undefined; i += 1; - if ( lines[i].startsWith('#EXT-X-ASSET:CAID') ) { - toLog.push(`\t${lines[i]}`); - lines[i] = undefined; i += 1; - } - if ( lines[i].startsWith('#EXT-X-SCTE35:') ) { - toLog.push(`\t${lines[i]}`); - lines[i] = undefined; i += 1; - } - if ( lines[i].startsWith('#EXT-X-CUE-IN') ) { - toLog.push(`\t${lines[i]}`); - lines[i] = undefined; i += 1; - } - if ( lines[i].startsWith('#EXT-X-SCTE35:') ) { - toLog.push(`\t${lines[i]}`); - lines[i] = undefined; i += 1; - } - return true; - }; - const pruneInfBlock = (lines, i) => { - if ( lines[i].startsWith('#EXTINF') === false ) { return false; } - if ( reM3u.test(lines[i+1]) === false ) { return false; } - toLog.push('Discarding', `\t${lines[i]}, \t${lines[i+1]}`); - lines[i] = lines[i+1] = undefined; i += 2; - if ( lines[i].startsWith('#EXT-X-DISCONTINUITY') ) { - toLog.push(`\t${lines[i]}`); - lines[i] = undefined; i += 1; - } - return true; - }; - const pruner = text => { - if ( (/^\s*#EXTM3U/.test(text)) === false ) { return text; } - if ( m3uPattern === '' ) { - safe.uboLog(` Content:\n${text}`); - return text; - } - if ( reM3u.multiline ) { - reM3u.lastIndex = 0; - for (;;) { - const match = reM3u.exec(text); - if ( match === null ) { break; } - let discard = match[0]; - let before = text.slice(0, match.index); - if ( - /^[\n\r]+/.test(discard) === false && - /[\n\r]+$/.test(before) === false - ) { - const startOfLine = /[^\n\r]+$/.exec(before); - if ( startOfLine !== null ) { - before = before.slice(0, startOfLine.index); - discard = startOfLine[0] + discard; - } - } - let after = text.slice(match.index + match[0].length); - if ( - /[\n\r]+$/.test(discard) === false && - /^[\n\r]+/.test(after) === false - ) { - const endOfLine = /^[^\n\r]+/.exec(after); - if ( endOfLine !== null ) { - after = after.slice(endOfLine.index); - discard += discard + endOfLine[0]; - } - } - text = before.trim() + '\n' + after.trim(); - reM3u.lastIndex = before.length + 1; - toLog.push('Discarding', ...discard.split(/\n+/).map(s => `\t${s}`)); - if ( reM3u.global === false ) { break; } - } - return text; - } - const lines = text.split(/\n\r|\n|\r/); - for ( let i = 0; i < lines.length; i++ ) { - if ( lines[i] === undefined ) { continue; } - if ( pruneSpliceoutBlock(lines, i) ) { continue; } - if ( pruneInfBlock(lines, i) ) { continue; } - } - return lines.filter(l => l !== undefined).join('\n'); - }; - const urlFromArg = arg => { - if ( typeof arg === 'string' ) { return arg; } - if ( arg instanceof Request ) { return arg.url; } - return String(arg); - }; - const realFetch = self.fetch; - self.fetch = new Proxy(self.fetch, { - apply: function(target, thisArg, args) { - if ( reUrl.test(urlFromArg(args[0])) === false ) { - return Reflect.apply(target, thisArg, args); - } - return realFetch(...args).then(realResponse => - realResponse.text().then(text => { - const response = new Response(pruner(text), { - status: realResponse.status, - statusText: realResponse.statusText, - headers: realResponse.headers, - }); - if ( toLog.length !== 0 ) { - toLog.unshift(logPrefix); - safe.uboLog(toLog.join('\n')); - } - return response; - }) - ); - } - }); - self.XMLHttpRequest.prototype.open = new Proxy(self.XMLHttpRequest.prototype.open, { - apply: async (target, thisArg, args) => { - if ( reUrl.test(urlFromArg(args[1])) === false ) { - return Reflect.apply(target, thisArg, args); - } - thisArg.addEventListener('readystatechange', function() { - if ( thisArg.readyState !== 4 ) { return; } - const type = thisArg.responseType; - if ( type !== '' && type !== 'text' ) { return; } - const textin = thisArg.responseText; - const textout = pruner(textin); - if ( textout === textin ) { return; } - Object.defineProperty(thisArg, 'response', { value: textout }); - Object.defineProperty(thisArg, 'responseText', { value: textout }); - if ( toLog.length !== 0 ) { - toLog.unshift(logPrefix); - safe.uboLog(toLog.join('\n')); - } - }); - return Reflect.apply(target, thisArg, args); - } - }); -} - -/******************************************************************************* - * - * @scriptlet href-sanitizer - * - * @description - * Set the `href` attribute to a value found in the DOM at, or below the - * targeted `a` element. - * - * ### Syntax - * - * ```text - * example.org##+js(href-sanitizer, selector [, source]) - * ``` - * - * - `selector`: required, CSS selector, specifies `a` elements for which the - * `href` attribute must be overridden. - * - `source`: optional, default to `text`, specifies from where to get the - * value which will override the `href` attribute. - * - `text`: the value will be the first valid URL found in the text - * content of the targeted `a` element. - * - `[attr]`: the value will be the attribute _attr_ of the targeted `a` - * element. - * - `?param`: the value will be the query parameter _param_ of the URL - * found in the `href` attribute of the targeted `a` element. - * - * ### Examples - * - * example.org##+js(href-sanitizer, a) - * example.org##+js(href-sanitizer, a[title], [title]) - * example.org##+js(href-sanitizer, a[href*="/away.php?to="], ?to) - * - * */ - -builtinScriptlets.push({ - name: 'href-sanitizer.js', - fn: hrefSanitizer, - world: 'ISOLATED', - dependencies: [ - 'run-at.fn', - 'safe-self.fn', - ], -}); -function hrefSanitizer( - selector = '', - source = '' -) { - if ( typeof selector !== 'string' ) { return; } - if ( selector === '' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('href-sanitizer', selector, source); - if ( source === '' ) { source = 'text'; } - const sanitizeCopycats = (href, text) => { - let elems = []; - try { - elems = document.querySelectorAll(`a[href="${href}"`); - } - catch(ex) { - } - for ( const elem of elems ) { - elem.setAttribute('href', text); - } - return elems.length; - }; - const validateURL = text => { - if ( text === '' ) { return ''; } - if ( /[^\x21-\x7e]/.test(text) ) { return ''; } - try { - const url = new URL(text, document.location); - return url.href; - } catch(ex) { - } - return ''; - }; - 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 ''; - } - if ( source === 'text' ) { - return elem.textContent - .replace(/^[^\x21-\x7e]+/, '') // remove leading invalid characters - .replace(/[^\x21-\x7e]+$/, '') // remove trailing invalid characters - ; - } - return ''; - }; - const sanitize = ( ) => { - let elems = []; - try { - elems = document.querySelectorAll(selector); - } - catch(ex) { - return false; - } - for ( const elem of elems ) { - if ( elem.localName !== 'a' ) { continue; } - if ( elem.hasAttribute('href') === false ) { continue; } - const href = elem.getAttribute('href'); - const text = extractText(elem, source); - const hrefAfter = validateURL(text); - if ( hrefAfter === '' ) { continue; } - if ( hrefAfter === href ) { continue; } - elem.setAttribute('href', hrefAfter); - const count = sanitizeCopycats(href, hrefAfter); - safe.uboLog(logPrefix, `Sanitized ${count+1} links to\n${hrefAfter}`); - } - return true; - }; - let observer, timer; - const onDomChanged = mutations => { - if ( timer !== undefined ) { return; } - let shouldSanitize = false; - for ( const mutation of mutations ) { - if ( mutation.addedNodes.length === 0 ) { continue; } - for ( const node of mutation.addedNodes ) { - if ( node.nodeType !== 1 ) { continue; } - shouldSanitize = true; - break; - } - if ( shouldSanitize ) { break; } - } - if ( shouldSanitize === false ) { return; } - timer = safe.onIdle(( ) => { - timer = undefined; - sanitize(); - }); - }; - const start = ( ) => { - if ( sanitize() === false ) { return; } - observer = new MutationObserver(onDomChanged); - observer.observe(document.body, { - subtree: true, - childList: true, - }); - }; - runAt(( ) => { start(); }, 'interactive'); -} - -/******************************************************************************* - * - * @scriptlet call-nothrow - * - * @description - * Prevent a function call from throwing. The function will be called, however - * should it throw, the scriptlet will silently process the exception and - * returns as if no exception has occurred. - * - * ### Syntax - * - * ```text - * example.org##+js(call-nothrow, propertyChain) - * ``` - * - * - `propertyChain`: a chain of dot-separated properties which leads to the - * function to be trapped. - * - * ### Examples - * - * example.org##+js(call-nothrow, Object.defineProperty) - * - * */ - -builtinScriptlets.push({ - name: 'call-nothrow.js', - fn: callNothrow, -}); -function callNothrow( - chain = '' -) { - if ( typeof chain !== 'string' ) { return; } - if ( chain === '' ) { return; } - const parts = chain.split('.'); - let owner = window, prop; - for (;;) { - prop = parts.shift(); - if ( parts.length === 0 ) { break; } - owner = owner[prop]; - if ( owner instanceof Object === false ) { return; } - } - if ( prop === '' ) { return; } - const fn = owner[prop]; - if ( typeof fn !== 'function' ) { return; } - owner[prop] = new Proxy(fn, { - apply: function(...args) { - let r; - try { - r = Reflect.apply(...args); - } 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'); -} - -/******************************************************************************* - * - * @scriptlet prevent-canvas - * - * @description - * Prevent usage of specific or all (default) canvas APIs. - * - * ### Syntax - * - * ```text - * example.com##+js(prevent-canvas [, contextType]) - * ``` - * - * - `contextType`: A specific type of canvas API to prevent (default to all - * APIs). Can be a string or regex which will be matched against the type - * used in getContext() call. Prepend with `!` to test for no-match. - * - * ### Examples - * - * 1. Prevent `example.com` from accessing all canvas APIs - * - * ```adblock - * example.com##+js(prevent-canvas) - * ``` - * - * 2. Prevent access to any flavor of WebGL API, everywhere - * - * ```adblock - * *##+js(prevent-canvas, /webgl/) - * ``` - * - * 3. Prevent `example.com` from accessing any flavor of canvas API except `2d` - * - * ```adblock - * example.com##+js(prevent-canvas, !2d) - * ``` - * - * ### References - * - * https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext - * - * */ - -builtinScriptlets.push({ - name: 'prevent-canvas.js', - fn: preventCanvas, - dependencies: [ - 'safe-self.fn', - ], -}); -function preventCanvas( - contextType = '' -) { - const safe = safeSelf(); - const pattern = safe.initPattern(contextType, { canNegate: true }); - const proto = globalThis.HTMLCanvasElement.prototype; - proto.getContext = new Proxy(proto.getContext, { - apply(target, thisArg, args) { - if ( safe.testPattern(pattern, args[0]) ) { return null; } - return Reflect.apply(target, thisArg, args); - } - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'multiup.js', - fn: multiup, - world: 'ISOLATED', -}); -function multiup() { - const handler = ev => { - const target = ev.target; - if ( target.matches('button[link]') === false ) { return; } - const ancestor = target.closest('form'); - if ( ancestor === null ) { return; } - if ( ancestor !== target.parentElement ) { return; } - const link = (target.getAttribute('link') || '').trim(); - if ( link === '' ) { return; } - ev.preventDefault(); - ev.stopPropagation(); - document.location.href = link; - }; - 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}`); - }); - } - }); - }); - } - }); -} - - -/******************************************************************************* - * - * Scriplets below this section are only available for filter lists from - * trusted sources. They all have the property `requiresTrust` set to `true`. - * - * Trusted sources are: - * - * - uBO's own filter lists, which name starts with "uBlock filters – ", and - * maintained at: https://github.com/uBlockOrigin/uAssets - * - * - The user's own filters as seen in "My filters" pane in uBO's dashboard. - * - * The trustworthiness of filters using these privileged scriptlets are - * evaluated at filter list compiled time: when a filter using one of the - * privileged scriptlet originates from a non-trusted filter list source, it - * is discarded at compile time, specifically from within: - * - * - Source: ./src/js/scriptlet-filtering.js - * - Method: scriptletFilteringEngine.compile(), via normalizeRawFilter() - * - **/ - -/******************************************************************************* - * - * replace-node-text.js - * - * Replace text instance(s) with another text instance inside specific - * DOM nodes. By default, the scriplet stops and quits at the interactive - * stage of a document. - * - * See commit messages for usage: - * - https://github.com/gorhill/uBlock/commit/99ce027fd702 - * - https://github.com/gorhill/uBlock/commit/41876336db48 - * - **/ - -builtinScriptlets.push({ - name: 'trusted-replace-node-text.js', - requiresTrust: true, - aliases: [ - 'trusted-rpnt.js', - 'replace-node-text.js', - 'rpnt.js', - ], - fn: replaceNodeText, - world: 'ISOLATED', - dependencies: [ - 'replace-node-text.fn', - ], -}); -function replaceNodeText( - nodeName, - pattern, - replacement, - ...extraArgs -) { - 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 - * - * Replaces response text content of fetch requests if all given parameters - * match. - * - * Reference: - * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/trusted-replace-fetch-response.js - * - **/ - -builtinScriptlets.push({ - name: 'trusted-replace-fetch-response.js', - requiresTrust: true, - aliases: [ - 'trusted-rpfr.js', - ], - fn: trustedReplaceFetchResponse, - dependencies: [ - 'replace-fetch-response.fn', - ], -}); -function trustedReplaceFetchResponse(...args) { - replaceFetchResponseFn(true, ...args); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'trusted-replace-xhr-response.js', - requiresTrust: true, - fn: trustedReplaceXhrResponse, - dependencies: [ - 'match-object-properties.fn', - 'parse-properties-to-match.fn', - 'safe-self.fn', - ], -}); -function trustedReplaceXhrResponse( - pattern = '', - replacement = '', - propsToMatch = '' -) { - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('trusted-replace-xhr-response', pattern, replacement, propsToMatch); - const xhrInstances = new WeakMap(); - if ( pattern === '*' ) { pattern = '.*'; } - const rePattern = safe.patternToRegex(pattern); - const propNeedles = parsePropertiesToMatch(propsToMatch, 'url'); - self.XMLHttpRequest = class extends self.XMLHttpRequest { - open(method, url, ...args) { - const outerXhr = this; - const xhrDetails = { method, url }; - let outcome = 'match'; - if ( propNeedles.size !== 0 ) { - if ( matchObjectProperties(propNeedles, xhrDetails) === false ) { - outcome = 'nomatch'; - } - } - if ( outcome === 'match' ) { - if ( safe.logLevel > 1 ) { - safe.uboLog(logPrefix, `Matched "propsToMatch"`); - } - xhrInstances.set(outerXhr, xhrDetails); - } - return super.open(method, url, ...args); - } - get response() { - const innerResponse = super.response; - const xhrDetails = xhrInstances.get(this); - if ( xhrDetails === undefined ) { - return innerResponse; - } - const responseLength = typeof innerResponse === 'string' - ? innerResponse.length - : undefined; - if ( xhrDetails.lastResponseLength !== responseLength ) { - xhrDetails.response = undefined; - xhrDetails.lastResponseLength = responseLength; - } - if ( xhrDetails.response !== undefined ) { - return xhrDetails.response; - } - if ( typeof innerResponse !== 'string' ) { - return (xhrDetails.response = innerResponse); - } - const textBefore = innerResponse; - const textAfter = textBefore.replace(rePattern, replacement); - if ( textAfter !== textBefore ) { - safe.uboLog(logPrefix, 'Match'); - } - return (xhrDetails.response = textAfter); - } - get responseText() { - const response = this.response; - if ( typeof response !== 'string' ) { - return super.responseText; - } - return response; - } - }; -} - -/******************************************************************************* - * - * trusted-click-element.js - * - * Reference API: - * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/trusted-click-element.js - * - **/ - -builtinScriptlets.push({ - name: 'trusted-click-element.js', - requiresTrust: true, - fn: trustedClickElement, - world: 'ISOLATED', - dependencies: [ - 'get-all-cookies.fn', - 'get-all-local-storage.fn', - 'run-at-html-element.fn', - 'safe-self.fn', - ], -}); -function trustedClickElement( - selectors = '', - extraMatch = '', - delay = '' -) { - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('trusted-click-element', selectors, extraMatch, delay); - - if ( extraMatch !== '' ) { - const assertions = extraMatch.split(',').map(s => { - const pos1 = s.indexOf(':'); - const s1 = pos1 !== -1 ? s.slice(0, pos1) : s; - const not = s1.startsWith('!'); - const type = not ? s1.slice(1) : s1; - const s2 = pos1 !== -1 ? s.slice(pos1+1).trim() : ''; - if ( s2 === '' ) { return; } - const out = { not, type }; - const match = /^\/(.+)\/(i?)$/.exec(s2); - if ( match !== null ) { - out.re = new RegExp(match[1], match[2] || undefined); - return out; - } - const pos2 = s2.indexOf('='); - const key = pos2 !== -1 ? s2.slice(0, pos2).trim() : s2; - const value = pos2 !== -1 ? s2.slice(pos2+1).trim() : ''; - out.re = new RegExp(`^${this.escapeRegexChars(key)}=${this.escapeRegexChars(value)}`); - return out; - }).filter(details => details !== undefined); - const allCookies = assertions.some(o => o.type === 'cookie') - ? getAllCookiesFn() - : []; - const allStorageItems = assertions.some(o => o.type === 'localStorage') - ? getAllLocalStorageFn() - : []; - const hasNeedle = (haystack, needle) => { - for ( const { key, value } of haystack ) { - if ( needle.test(`${key}=${value}`) ) { return true; } - } - return false; - }; - for ( const { not, type, re } of assertions ) { - switch ( type ) { - case 'cookie': - if ( hasNeedle(allCookies, re) === not ) { return; } - break; - case 'localStorage': - if ( hasNeedle(allStorageItems, re) === not ) { return; } - break; - } - } - } - - const getShadowRoot = elem => { - // Firefox - if ( elem.openOrClosedShadowRoot ) { - return elem.openOrClosedShadowRoot; - } - // Chromium - if ( typeof chrome === 'object' ) { - if ( chrome.dom && chrome.dom.openOrClosedShadowRoot ) { - return chrome.dom.openOrClosedShadowRoot(elem); - } - } - return null; - }; - - const querySelectorEx = (selector, context = document) => { - const pos = selector.indexOf(' >>> '); - if ( pos === -1 ) { return context.querySelector(selector); } - const outside = selector.slice(0, pos).trim(); - const inside = selector.slice(pos + 5).trim(); - const elem = context.querySelector(outside); - if ( elem === null ) { return null; } - const shadowRoot = getShadowRoot(elem); - return shadowRoot && querySelectorEx(inside, shadowRoot); - }; - - const selectorList = selectors.split(/\s*,\s*/) - .filter(s => { - try { - void querySelectorEx(s); - } catch(_) { - return false; - } - return true; - }); - if ( selectorList.length === 0 ) { return; } - - const clickDelay = parseInt(delay, 10) || 1; - const t0 = Date.now(); - const tbye = t0 + 10000; - let tnext = selectorList.length !== 1 ? t0 : t0 + clickDelay; - - const terminate = ( ) => { - selectorList.length = 0; - next.stop(); - observe.stop(); - }; - - const next = notFound => { - if ( selectorList.length === 0 ) { - safe.uboLog(logPrefix, 'Completed'); - return terminate(); - } - const tnow = Date.now(); - if ( tnow >= tbye ) { - safe.uboLog(logPrefix, 'Timed out'); - return terminate(); - } - if ( notFound ) { observe(); } - const delay = Math.max(notFound ? tbye - tnow : tnext - tnow, 1); - next.timer = setTimeout(( ) => { - next.timer = undefined; - process(); - }, delay); - safe.uboLog(logPrefix, `Waiting for ${selectorList[0]}...`); - }; - next.stop = ( ) => { - if ( next.timer === undefined ) { return; } - clearTimeout(next.timer); - next.timer = undefined; - }; - - const observe = ( ) => { - if ( observe.observer !== undefined ) { return; } - observe.observer = new MutationObserver(( ) => { - if ( observe.timer !== undefined ) { return; } - observe.timer = setTimeout(( ) => { - observe.timer = undefined; - process(); - }, 20); - }); - observe.observer.observe(document, { - attributes: true, - childList: true, - subtree: true, - }); - }; - observe.stop = ( ) => { - if ( observe.timer !== undefined ) { - clearTimeout(observe.timer); - observe.timer = undefined; - } - if ( observe.observer ) { - observe.observer.disconnect(); - observe.observer = undefined; - } - }; - - const process = ( ) => { - next.stop(); - if ( Date.now() < tnext ) { return next(); } - const selector = selectorList.shift(); - if ( selector === undefined ) { return terminate(); } - const elem = querySelectorEx(selector); - if ( elem === null ) { - selectorList.unshift(selector); - return next(true); - } - safe.uboLog(logPrefix, `Clicked ${selector}`); - elem.click(); - tnext += clickDelay; - next(); - }; - - runAtHtmlElementFn(process); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'trusted-prune-inbound-object.js', - requiresTrust: true, - fn: trustedPruneInboundObject, - dependencies: [ - 'object-find-owner.fn', - 'object-prune.fn', - 'safe-self.fn', - ], -}); -function trustedPruneInboundObject( - entryPoint = '', - argPos = '', - rawPrunePaths = '', - rawNeedlePaths = '' -) { - if ( entryPoint === '' ) { return; } - let context = globalThis; - let prop = entryPoint; - for (;;) { - const pos = prop.indexOf('.'); - if ( pos === -1 ) { break; } - context = context[prop.slice(0, pos)]; - if ( context instanceof Object === false ) { return; } - prop = prop.slice(pos+1); - } - if ( typeof context[prop] !== 'function' ) { return; } - const argIndex = parseInt(argPos); - if ( isNaN(argIndex) ) { return; } - if ( argIndex < 1 ) { return; } - const safe = safeSelf(); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 4); - const needlePaths = []; - if ( rawPrunePaths !== '' ) { - needlePaths.push(...rawPrunePaths.split(/ +/)); - } - if ( rawNeedlePaths !== '' ) { - needlePaths.push(...rawNeedlePaths.split(/ +/)); - } - const stackNeedle = safe.initPattern(extraArgs.stackToMatch || '', { canNegate: true }); - const mustProcess = root => { - for ( const needlePath of needlePaths ) { - if ( objectFindOwnerFn(root, needlePath) === false ) { - return false; - } - } - return true; - }; - context[prop] = new Proxy(context[prop], { - apply: function(target, thisArg, args) { - const targetArg = argIndex <= args.length - ? args[argIndex-1] - : undefined; - if ( targetArg instanceof Object && mustProcess(targetArg) ) { - let objBefore = targetArg; - if ( extraArgs.dontOverwrite ) { - try { - objBefore = safe.JSON_parse(safe.JSON_stringify(targetArg)); - } catch(_) { - objBefore = undefined; - } - } - if ( objBefore !== undefined ) { - const objAfter = objectPruneFn( - objBefore, - rawPrunePaths, - rawNeedlePaths, - stackNeedle, - extraArgs - ); - args[argIndex-1] = objAfter || objBefore; - } - } - return Reflect.apply(target, thisArg, args); - }, - }); -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'trusted-prune-outbound-object.js', - requiresTrust: true, - fn: trustedPruneOutboundObject, - dependencies: [ - 'object-prune.fn', - 'proxy-apply.fn', - 'safe-self.fn', - ], -}); -function trustedPruneOutboundObject( - propChain = '', - rawPrunePaths = '', - rawNeedlePaths = '' -) { - if ( propChain === '' ) { return; } - const safe = safeSelf(); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); - const reflector = proxyApplyFn(propChain, function(...args) { - const objBefore = reflector(...args); - if ( objBefore instanceof Object === false ) { return objBefore; } - const objAfter = objectPruneFn( - objBefore, - rawPrunePaths, - rawNeedlePaths, - { matchAll: true }, - extraArgs - ); - return objAfter || objBefore; - }); -} - -/******************************************************************************/ - -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, - fn: trustedReplaceOutboundText, - dependencies: [ - 'proxy-apply.fn', - 'safe-self.fn', - ], -}); -function trustedReplaceOutboundText( - propChain = '', - pattern = '', - replacement = '', - ...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 extraArgs = safe.getExtraArgs(args); - const reCondition = safe.patternToRegex(extraArgs.condition || ''); - const reflector = proxyApplyFn(propChain, function(...args) { - const encodedTextBefore = reflector(...args); - let textBefore = encodedTextBefore; - if ( extraArgs.encoding === 'base64' ) { - try { textBefore = self.atob(encodedTextBefore); } - catch(ex) { return encodedTextBefore; } - } - if ( pattern === '' ) { - safe.uboLog(logPrefix, 'Decoded outbound text:\n', textBefore); - return encodedTextBefore; - } - reCondition.lastIndex = 0; - if ( reCondition.test(textBefore) === false ) { return encodedTextBefore; } - const textAfter = textBefore.replace(rePattern, replacement); - if ( textAfter === textBefore ) { return encodedTextBefore; } - safe.uboLog(logPrefix, 'Matched and replaced'); - if ( safe.logLevel > 1 ) { - safe.uboLog(logPrefix, 'Modified decoded outbound text:\n', textAfter); - } - let encodedTextAfter = textAfter; - if ( extraArgs.encoding === 'base64' ) { - encodedTextAfter = self.btoa(textAfter); - } - return encodedTextAfter; - }); -} - -/******************************************************************************/ 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.js b/dist/chromium/publish-stable.js new file mode 100644 index 0000000000000..74c000b778917 --- /dev/null +++ b/dist/chromium/publish-stable.js @@ -0,0 +1,160 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import * as fs from 'node:fs/promises'; +import * as ghapi from '../github-api.js'; +import path from 'node:path'; +import process from 'node:process'; + +/******************************************************************************/ + +const secrets = await ghapi.getSecrets(); +const githubAuth = `Bearer ${secrets.github_token}`; +const commandLineArgs = ghapi.commandLineArgs; +const githubOwner = commandLineArgs.ghowner; +const githubRepo = commandLineArgs.ghrepo; +const githubTag = commandLineArgs.ghtag; +const cwsId = commandLineArgs.cwsid; + +/******************************************************************************/ + +async function publishToCWS(filePath) { + // Prepare access token + console.log('Generating access token...'); + const authURL = 'https://accounts.google.com/o/oauth2/token'; + const authRequest = new Request(authURL, { + body: JSON.stringify({ + client_id: secrets.cs_id, + client_secret: secrets.cs_secret, + grant_type: 'refresh_token', + refresh_token: secrets.cs_refresh, + }), + method: 'POST', + }); + const authResponse = await fetch(authRequest); + if ( authResponse.ok === false ) { + console.error(`Error: Auth failed -- server error ${authResponse.statusText}`); + process.exit(1); + } + const responseDict = await authResponse.json() + if ( responseDict.access_token === undefined ) { + console.error('Error: Auth failed -- no access token'); + console.error('Error: Auth failed --', JSON.stringify(responseDict, null, 2)); + process.exit(1); + } + const cwsAuth = `Bearer ${responseDict.access_token}`; + if ( responseDict.refresh_token ) { + secrets.cs_refresh = responseDict.refresh_token + } + + // Read package + const data = await fs.readFile(filePath); + + // Upload + console.log('Uploading package...') + const uploadURL = `https://www.googleapis.com/upload/chromewebstore/v1.1/items/${cwsId}`; + const uploadRequest = new Request(uploadURL, { + body: data, + headers: { + 'Authorization': cwsAuth, + 'x-goog-api-version': '2', + }, + method: 'PUT', + }); + const uploadResponse = await fetch(uploadRequest); + if ( uploadResponse.ok === false ) { + console.error(`Upload failed -- server error ${uploadResponse.statusText}`); + process.exit(1) + } + const uploadDict = await uploadResponse.json(); + if ( uploadDict.uploadState !== 'SUCCESS' ) { + console.error(`Upload failed -- server error ${uploadDict['uploadState']}`); + process.exit(1); + } + console.log('Upload succeeded.') + + // Publish + console.log('Publishing package...') + const publishURL = `https://www.googleapis.com/chromewebstore/v1.1/items/${cwsId}/publish`; + const publishRequest = new Request(publishURL, { + headers: { + 'Authorization': cwsAuth, + 'x-goog-api-version': '2', + 'Content-Length': '0', + }, + method: 'POST', + }); + const publishResponse = await fetch(publishRequest); + if ( publishResponse.ok === false ) { + console.error(`Error: Chrome store publishing failed -- server error ${publishResponse.statusText}`); + process.exit(1); + } + const publishDict = await publishResponse.json(); + if ( + Array.isArray(publishDict.status) === false || + publishDict.status.includes('OK') === false + ) { + console.error(`Publishing failed -- server error ${publishDict.status}`); + process.exit(1); + } + console.log('Publishing succeeded.') +} + +/******************************************************************************/ + +async function main() { + if ( secrets === undefined ) { return 'Need secrets'; } + if ( githubOwner === '' ) { return 'Need GitHub owner'; } + if ( githubRepo === '' ) { return 'Need GitHub repo'; } + + ghapi.setGithubContext(githubOwner, githubRepo, githubTag, githubAuth); + + const assetInfo = await ghapi.getAssetInfo('chromium'); + + console.log(`GitHub owner: "${githubOwner}"`); + console.log(`GitHub repo: "${githubRepo}"`); + console.log(`Release tag: "${githubTag}"`); + console.log(`Release asset: "${assetInfo.name}"`); + + // Fetch asset from GitHub repo + const filePath = await ghapi.downloadAssetFromRelease(assetInfo); + console.log('Asset saved at', filePath); + + // Upload to Chrome Web Store + await publishToCWS(filePath); + + // Clean up + if ( commandLineArgs.keep !== true ) { + const tmpdir = path.dirname(filePath); + console.log(`Removing ${tmpdir}`); + ghapi.shellExec(`rm -rf "${tmpdir}"`); + } + + console.log('Done'); +} + +main().then(result => { + if ( result !== undefined ) { + console.log(result); + process.exit(1); + } + process.exit(0); +}); 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..96ceec5b4c2a3 100644 --- a/dist/firefox/updates.json +++ b/dist/firefox/updates.json @@ -3,9 +3,9 @@ "uBlock0@raymondhill.net": { "updates": [ { - "version": "1.58.1.3", - "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" + "version": "1.64.1.10", + "browser_specific_settings": { "gecko": { "strict_min_version": "92.0" } }, + "update_link": "https://github.com/gorhill/uBlock/releases/download/1.64.1b10/uBlock0_1.64.1b10.firefox.signed.xpi" } ] } diff --git a/dist/firefox/upload-signed-beta.py b/dist/firefox/upload-signed-beta.py new file mode 100755 index 0000000000000..5c9588376dd7f --- /dev/null +++ b/dist/firefox/upload-signed-beta.py @@ -0,0 +1,257 @@ +#!/usr/bin/env python3 + +import datetime +import json +import jwt +import os +import re +import requests +import subprocess +import sys +import tempfile + +from string import Template + +# - Download target (raw) uBlock0.firefox.xpi from GitHub +# - This is referred to as "raw" package +# - This will fail if not a dev build +# - Modify raw package to make it self-hosted +# - This is referred to as "unsigned" package +# - Ask AMO to sign uBlock0.firefox.xpi +# - Generate JWT to be used for communication with server +# - Upload unsigned package to AMO +# - Wait for a valid download URL for signed package +# - Download signed package as uBlock0.firefox.signed.xpi +# - This is referred to as "signed" package +# - Upload uBlock0.firefox.signed.xpi to GitHub +# - Remove uBlock0.firefox.xpi from GitHub +# - Modify updates.json to point to new version +# - Commit changes to repo + +# Find path to project root +projdir = os.path.split(os.path.abspath(__file__))[0] +while not os.path.isdir(os.path.join(projdir, '.git')): + projdir = os.path.normpath(os.path.join(projdir, '..')) +# Check that found project root is valid +version_filepath = os.path.join(projdir, 'dist', 'version') +if not os.path.isfile(version_filepath): + print('Version file not found.') + exit(1) + +# We need a version string to work with +if len(sys.argv) >= 2 and sys.argv[1]: + tag_version = sys.argv[1] +else: + tag_version = input('Github release version: ') +tag_version.strip() +match = re.search('^(\d+\.\d+\.\d+)(?:(b|rc)(\d+))?$', tag_version) +if not match: + print('Error: Invalid version string.') + exit(1) +ext_version = match.group(1); +if match.group(2): + revision = int(match.group(3)) + if match.group(2) == 'rc': + revision += 100; + ext_version += '.' + str(revision) + +extension_id = 'uBlock0@raymondhill.net' +tmpdir = tempfile.TemporaryDirectory() +raw_xpi_filename = 'uBlock0_' + tag_version + '.firefox.xpi' +raw_xpi_filepath = os.path.join(tmpdir.name, raw_xpi_filename) +unsigned_xpi_filepath = os.path.join(tmpdir.name, 'uBlock0.firefox.unsigned.xpi') +signed_xpi_filename = 'uBlock0_' + tag_version + '.firefox.signed.xpi' +signed_xpi_filepath = os.path.join(tmpdir.name, signed_xpi_filename) +github_owner = 'gorhill' +github_repo = 'uBlock' + +# Load/save auth secrets +# The tmp directory is excluded from git +ubo_secrets = dict() +ubo_secrets_filename = os.path.join(projdir, 'tmp', 'ubo_secrets') +if os.path.isfile(ubo_secrets_filename): + with open(ubo_secrets_filename) as f: + ubo_secrets = json.load(f) + +def input_secret(prompt, token): + if token in ubo_secrets: + prompt += ' ✔' + prompt += ': ' + value = input(prompt).strip() + if len(value) == 0: + if token not in ubo_secrets: + print('Token error:', token) + exit(1) + value = ubo_secrets[token] + elif token not in ubo_secrets or value != ubo_secrets[token]: + ubo_secrets[token] = value + exists = os.path.isfile(ubo_secrets_filename) + with open(ubo_secrets_filename, 'w') as f: + json.dump(ubo_secrets, f, indent=2) + if not exists: + os.chmod(ubo_secrets_filename, 0o600) + return value + +# GitHub API token +github_token = input_secret('Github token', 'github_token') +github_auth = 'token ' + github_token + +# +# Get metadata from GitHub about the release +# + +# https://developer.github.com/v3/repos/releases/#get-a-single-release +print('Downloading release info from GitHub...') +release_info_url = 'https://api.github.com/repos/{0}/{1}/releases/tags/{2}'.format(github_owner, github_repo, tag_version) +headers = { 'Authorization': github_auth, } +response = requests.get(release_info_url, headers=headers) +if response.status_code != 200: + print('Error: Release not found: {0}'.format(response.status_code)) + exit(1) +release_info = response.json() + +# +# Extract URL to raw package from metadata +# + +# Find url for uBlock0.firefox.xpi +raw_xpi_url = '' +for asset in release_info['assets']: + if asset['name'] == signed_xpi_filename: + print('Error: Found existing signed self-hosted package.') + exit(1) + if asset['name'] == raw_xpi_filename: + raw_xpi_url = asset['url'] +if len(raw_xpi_url) == 0: + print('Error: Release asset URL not found') + exit(1) + +# +# Ask AMO to sign the self-hosted package +# - https://developer.mozilla.org/en-US/Add-ons/Distribution#Distributing_your_add-on +# - https://pyjwt.readthedocs.io/en/latest/usage.html +# - https://addons-server.readthedocs.io/en/latest/topics/api/auth.html +# - https://addons-server.readthedocs.io/en/latest/topics/api/signing.html +# + +amo_api_key = '' +amo_secret = '' + +def get_jwt_auth(): + global amo_api_key + if amo_api_key == '': + amo_api_key = input_secret('AMO API key', 'amo_api_key') + global amo_secret + if amo_secret == '': + amo_secret = input_secret('AMO API secret', 'amo_secret') + amo_nonce = os.urandom(8).hex() + jwt_payload = { + 'iss': amo_api_key, + 'jti': amo_nonce, + 'iat': datetime.datetime.utcnow(), + 'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=15), + } + return 'JWT ' + jwt.encode(jwt_payload, amo_secret) + +# https://blog.mozilla.org/addons/2019/11/11/security-improvements-in-amo-upload-tools/ +# "We recommend allowing up to 15 minutes." +headers = { 'Authorization': get_jwt_auth(), } +version_details_url = 'https://addons.mozilla.org/api/v5/addons/addon/{0}/versions/{1}/'.format(extension_id, ext_version) +print('Fetching package details...') +version_details_response = requests.get(version_details_url, headers=headers) +if version_details_response.status_code > 400: + print('Error: Fetching derails failed -- server error {0}'.format(version_details_response.status_code)) + print(version_details_response.text) + exit(1) +print('Fetching version details succeeded.') +version_details = version_details_response.json(); +if version_details['file']['status'] != 'public': + print('Error: Version is not approved -- server error {0}'.format(version_details_response.status_code)) + print(version_details_response.text) + exit(1) +if not version_details['file']['url']: + print('Error: No file URL') + print(version_details_response.text) + exit(1) +download_url = version_details['file']['url'] +print('Downloading signed self-hosted xpi package from {0}...'.format(download_url)) +response = requests.get(download_url, headers=headers) +if response.status_code != 200: + print('Error: Download signed package failed -- server error {0}'.format(response.status_code)) + print(response.text) + exit(1) +with open(signed_xpi_filepath, 'wb') as f: + f.write(response.content) + f.close() +print('Signed self-hosted xpi package downloaded.') + +# +# Upload signed package to GitHub +# + +# https://developer.github.com/v3/repos/releases/#upload-a-release-asset +print('Uploading signed self-hosted xpi package to GitHub...') +with open(signed_xpi_filepath, 'rb') as f: + url = release_info['upload_url'].replace('{?name,label}', '?name=' + signed_xpi_filename) + headers = { + 'Authorization': github_auth, + 'Content-Type': 'application/zip', + } + response = requests.post(url, headers=headers, data=f.read()) + if response.status_code != 201: + print('Error: Upload signed package failed -- server error: {0}'.format(response.status_code)) + exit(1) + +# +# Remove raw package from GitHub +# + +# https://developer.github.com/v3/repos/releases/#delete-a-release-asset +print('Remove raw xpi package from GitHub...') +headers = { 'Authorization': github_auth, } +response = requests.delete(raw_xpi_url, headers=headers) +if response.status_code != 204: + print('Error: Deletion of raw package failed -- server error: {0}'.format(response.status_code)) + +# +# Update updates.json to point to new package -- but only if just-signed +# package is higher version than current one. +# + +# Be sure we are in sync with potentially modified files on remote +r = subprocess.run(['git', 'pull', 'origin', 'master'], stdout=subprocess.PIPE) +rout = bytes.decode(r.stdout).strip() + +def int_from_version(version): + parts = version.split('.') + if len(parts) == 3: + parts.append('0') + return int(parts[0])*10e9 + int(parts[1])*10e6 + int(parts[2])*10e3 + int(parts[3]) + +print('Update GitHub to point to newly signed self-hosted xpi package...') +updates_json_filepath = os.path.join(projdir, 'dist', 'firefox', 'updates.json') +with open(updates_json_filepath) as f: + updates_json = json.load(f) + f.close() + previous_version = updates_json['addons'][extension_id]['updates'][0]['version'] + if int_from_version(ext_version) > int_from_version(previous_version): + with open(os.path.join(projdir, 'dist', 'firefox', 'updates.template.json')) as f: + template_json = Template(f.read()) + f.close() + updates_json = template_json.substitute(ext_version=ext_version, tag_version=tag_version, min_browser_version=version_details['compatibility']['firefox']['min']) + with open(updates_json_filepath, 'w') as f: + f.write(updates_json) + f.close() + # - Stage the changed file + r = subprocess.run(['git', 'status', '-s', updates_json_filepath], stdout=subprocess.PIPE) + rout = bytes.decode(r.stdout).strip() + if len(rout) >= 2 and rout[1] == 'M': + subprocess.run(['git', 'add', updates_json_filepath]) + # - Commit the staged file + r = subprocess.run(['git', 'status', '-s', updates_json_filepath], stdout=subprocess.PIPE) + rout = bytes.decode(r.stdout).strip() + if len(rout) >= 2 and rout[0] == 'M': + subprocess.run(['git', 'commit', '-m', 'Make Firefox dev build auto-update', updates_json_filepath]) + subprocess.run(['git', 'push', 'origin', 'HEAD']) + +print('All done.') diff --git a/dist/github-api.js b/dist/github-api.js new file mode 100644 index 0000000000000..0ba1e16710915 --- /dev/null +++ b/dist/github-api.js @@ -0,0 +1,223 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import * as fs from 'node:fs/promises'; +import { execSync } from 'node:child_process'; +import os from 'node:os'; +import path from 'node:path'; +import process from 'node:process'; + +/******************************************************************************/ + +function voidFunc() { +} + +/******************************************************************************/ + +let githubOwner = ''; +let githubRepo = ''; +let githubTag = ''; +let githubAuth = ''; + +export function setGithubContext(owner, repo, tag, auth) { + githubOwner = owner; + githubRepo = repo; + githubTag = tag; + githubAuth = auth; +} + +/******************************************************************************/ + +let pathToSecrets = ''; + +export async function getSecrets() { + const homeDir = os.homedir(); + let currentDir = process.cwd(); + let fileName = ''; + for (;;) { + fileName = `${currentDir}/ubo_secrets`; + const stat = await fs.stat(fileName).catch(voidFunc); + if ( stat !== undefined ) { break; } + currentDir = path.resolve(currentDir, '..'); + if ( currentDir.startsWith(homeDir) === false ) { + pathToSecrets = homeDir; + return; + } + } + console.log(`Found secrets in ${fileName}`); + const text = await fs.readFile(fileName, { encoding: 'utf8' }).catch(voidFunc); + if ( text === undefined ) { return {}; } + const secrets = JSON.parse(text); + pathToSecrets = fileName; + return secrets; +} + +export async function saveSecrets(secrets) { + if ( pathToSecrets === '' ) { return; } + return fs.writeFile(pathToSecrets, JSON.stringify(secrets, null, 2)); +} + +/******************************************************************************/ + +export async function getRepoRoot() { + const homeDir = os.homedir(); + let currentDir = process.cwd(); + for (;;) { + const fileName = `${currentDir}/.git`; + const stat = await fs.stat(fileName).catch(voidFunc); + if ( stat !== undefined ) { return currentDir; } + currentDir = path.resolve(currentDir, '..'); + if ( currentDir.startsWith(homeDir) === false ) { return; } + } +} + +/******************************************************************************/ + +export async function getReleaseInfo() { + console.log(`Fetching release info for ${githubOwner}/${githubRepo}/${githubTag} from GitHub`); + const releaseInfoUrl = `https://api.github.com/repos/${githubOwner}/${githubRepo}/releases/tags/${githubTag}`; + const request = new Request(releaseInfoUrl, { + headers: { + Authorization: githubAuth, + }, + }); + const response = await fetch(request).catch(voidFunc); + if ( response === undefined ) { return; } + if ( response.ok !== true ) { return; } + const releaseInfo = await response.json().catch(voidFunc); + if ( releaseInfo === undefined ) { return; } + return releaseInfo; +} + +/******************************************************************************/ + +export async function getAssetInfo(assetName) { + const releaseInfo = await getReleaseInfo(); + if ( releaseInfo === undefined ) { return; } + if ( releaseInfo.assets === undefined ) { return; } + for ( const asset of releaseInfo.assets ) { + if ( asset.name.includes(assetName) ) { return asset; } + } +} + +/******************************************************************************/ + +export async function downloadAssetFromRelease(assetInfo) { + const assetURL = assetInfo.url; + console.log(`Fetching ${assetURL}`); + const request = new Request(assetURL, { + headers: { + Authorization: githubAuth, + Accept: 'application/octet-stream', + }, + }); + const response = await fetch(request).catch(voidFunc); + if ( response.ok !== true ) { return; } + const data = await response.bytes().catch(voidFunc); + if ( data === undefined ) { return; } + const tempDir = await fs.mkdtemp('/tmp/github-asset-'); + const fileName = `${tempDir}/${assetInfo.name}`; + await fs.writeFile(fileName, data); + return fileName; +} + +/******************************************************************************/ + +export async function uploadAssetToRelease(assetPath, mimeType) { + console.log(`Uploading "${assetPath}" to GitHub...`); + const data = await fs.readFile(assetPath).catch(( ) => { }); + if ( data === undefined ) { return; } + const releaseInfo = await getReleaseInfo(); + if ( releaseInfo.upload_url === undefined ) { return; } + const assetName = path.basename(assetPath); + const uploadURL = releaseInfo.upload_url.replace('{?name,label}', `?name=${assetName}`); + console.log('Upload URL:', uploadURL); + const request = new Request(uploadURL, { + body: new Int8Array(data.buffer, data.byteOffset, data.length), + headers: { + Authorization: githubAuth, + 'Content-Type': mimeType, + }, + method: 'POST', + }); + const response = await fetch(request).catch(( ) => { }); + if ( response === undefined ) { return; } + const json = await response.json(); + console.log(json); + return json; +} + +/******************************************************************************/ + +export async function deleteAssetFromRelease(assetURL) { + print(`Remove ${assetURL} from GitHub release ${githubTag}...`); + const request = new Request(assetURL, { + headers: { + Authorization: githubAuth, + }, + method: 'DELETE', + }); + const response = await fetch(request); + return response.ok; +} + +/******************************************************************************/ + +export async function getManifest(path) { + const text = await fs.readFile(path, { encoding: 'utf8' }); + return JSON.parse(text); +} + +/******************************************************************************/ + +export async function shellExec(text) { + let command = ''; + for ( const line of text.split(/[\n\r]+/) ) { + command += line.trimEnd(); + if ( command.endsWith('\\') ) { + command = command.slice(0, -1); + continue; + } + command = command.trim(); + if ( command === '' ) { continue; } + execSync(command); + command = ''; + } +} + +/******************************************************************************/ + +export const commandLineArgs = (( ) => { + const args = Object.create(null); + let name, value; + for ( const arg of process.argv.slice(2) ) { + const pos = arg.indexOf('='); + if ( pos === -1 ) { + name = arg; + value = true; + } else { + name = arg.slice(0, pos); + value = arg.slice(pos+1); + } + args[name] = value; + } + return args; +})(); 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..bf38d3fcc0e8c 100644 --- a/dist/version +++ b/dist/version @@ -1 +1 @@ -1.58.1.3 \ No newline at end of file +1.65.1.0 \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000000000..f9bdca1ca9cd2 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,51 @@ +import js from "@eslint/js"; +import globals from "globals"; +import json from "@eslint/json"; + +import { includeIgnoreFile } from "@eslint/compat"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const gitignorePath = path.resolve(__dirname, ".gitignore"); + +export default [ includeIgnoreFile(gitignorePath), { + files: ["**/*.js", "**/*.mjs"], + ...js.configs.recommended, +}, { + files: ["**/*.js", "**/*.mjs"], + languageOptions: { + globals: { + ...globals.browser, + browser: "readonly", + chrome: "readonly", + vAPI: "readonly", + }, + sourceType: "module", + }, + rules: { + eqeqeq: ["warn", "always"], + indent: ["error", 4, { + ignoredNodes: [ + "Program > BlockStatement", + "Program > ExpressionStatement > CallExpression > ArrowFunctionExpression > BlockStatement", + "Program > ExpressionStatement > CallExpression > FunctionExpression > BlockStatement", + "Program > IfStatement > BlockStatement", + "Program > VariableDeclaration > VariableDeclarator > CallExpression > ArrowFunctionExpression > BlockStatement", + "CallExpression > MemberExpression", + "ArrayExpression > *", + "ObjectExpression > *", + ], + }], + "no-control-regex": "off", + "no-empty": "off", + "sort-imports": "error", + "strict": "error", + }, +}, { + files: ["**/*.json"], + ignores: ["package-lock.json"], + language: "json/json", + ...json.configs.recommended, +} ]; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000000..18b1c50b91002 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1146 @@ +{ + "name": "uBlock", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "uBlock", + "version": "1.0.0", + "license": "GPLv3", + "devDependencies": { + "@eslint/compat": "^1.2.4", + "@eslint/js": "^9.17.0", + "@eslint/json": "^0.9.0", + "eslint": "^9.17.0", + "eslint-formatter-compact": "^8.40.0", + "globals": "^15.14.0" + }, + "engines": { + "node": ">=22", + "npm": ">=11" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/compat": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.4.tgz", + "integrity": "sha512-S8ZdQj/N69YAtuqFt7653jwcvuUj131+6qGLUyDqfDg1OIoBQ66OCuXC473YQfO2AaxITTutiRQiDwoo7ZLYyg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^9.10.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/config-array": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz", + "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.5", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz", + "integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", + "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/json": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@eslint/json/-/json-0.9.0.tgz", + "integrity": "sha512-PTLD0Kp7+BKhTthodns+hFbuZZ+hjb3lc/iVAg7mtBAnW5hLJhkST9O4m21oMkxG94GR2+GGZQNNurG9KP8pNA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/plugin-kit": "^0.2.3", + "@humanwhocodes/momoa": "^3.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz", + "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz", + "integrity": "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/momoa": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/@humanwhocodes/momoa/-/momoa-3.3.6.tgz", + "integrity": "sha512-7/sAGm3YsT6xG1bDkTSHvOpQB+cR4I2InfMVw110nuOCrxZvOQHgRqBMxSoTeUQrk9RS4OU9Aw2MBMZVJgLZMg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz", + "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.17.0", + "@eslint/plugin-kit": "^0.2.3", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-formatter-compact": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/eslint-formatter-compact/-/eslint-formatter-compact-8.40.0.tgz", + "integrity": "sha512-cwGUs113TgmTQXecx5kfRjB7m0y2wkDLSadPTE2pK6M/wO4N8PjmUaoWOFNCP9MHgsiZwgqd5bZFnDCnszC56Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "dev": true, + "license": "ISC" + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "15.14.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz", + "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000000000..dc01c127dae4d --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "uBlock", + "version": "1.0.0", + "description": "npm dev tools", + "main": "index.js", + "scripts": { + "lint": "eslint --no-warn-ignored --ignore-pattern \"**/lib/\" --ignore-pattern \"**/npm/\" -- \"./src/js/*.js\" \"./src/js/**/*.js\" \"./**/*.json\" \"./platform/**/*.js\"", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/gorhill/uBlock.git" + }, + "author": "Raymond Hill", + "license": "GPLv3", + "bugs": { + "url": "https://github.com/gorhill/uBlock/issues" + }, + "homepage": "https://github.com/gorhill/uBlock#readme", + "engines": { + "node": ">=22", + "npm": ">=11" + }, + "devDependencies": { + "eslint": "^9.17.0", + "@eslint/compat": "^1.2.4", + "@eslint/js": "^9.17.0", + "@eslint/json": "^0.9.0", + "eslint-formatter-compact": "^8.40.0", + "globals": "^15.14.0" + } +} diff --git a/platform/browser/main.js b/platform/browser/main.js deleted file mode 100644 index d6f6acb9c69b1..0000000000000 --- a/platform/browser/main.js +++ /dev/null @@ -1,123 +0,0 @@ -/******************************************************************************* - - uBlock Origin - a browser extension to block requests. - Copyright (C) 2014-present Raymond Hill - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see {http://www.gnu.org/licenses/}. - - Home: https://github.com/gorhill/uBlock -*/ - -'use strict'; - -/******************************************************************************/ - -import publicSuffixList from './lib/publicsuffixlist/publicsuffixlist.js'; -import punycode from './lib/punycode.js'; - -import staticNetFilteringEngine from './js/static-net-filtering.js'; -import { FilteringContext } from './js/filtering-context.js'; -import { LineIterator } from './js/text-utils.js'; -import * as sfp from './js/static-filtering-parser.js'; - -import { - CompiledListReader, - CompiledListWriter -} from './js/static-filtering-io.js'; - -/******************************************************************************/ - -function compileList(rawText, writer) { - const lineIter = new LineIterator(rawText); - const parser = new sfp.AstFilterParser({ - interactive: true, - maxTokenLength: staticNetFilteringEngine.MAX_TOKEN_LENGTH, - }); - const compiler = staticNetFilteringEngine.createCompiler(); - - while ( lineIter.eot() === false ) { - let line = lineIter.next(); - - while ( line.endsWith(' \\') ) { - if ( lineIter.peek(4) !== ' ' ) { break; } - line = line.slice(0, -2).trim() + lineIter.next().trim(); - } - parser.parse(line); - - if ( parser.isFilter() === false ) { continue; } - if ( parser.isNetworkFilter() === false ) { continue; } - if ( compiler.compile(parser, writer) ) { continue; } - if ( compiler.error !== undefined ) { - console.info(JSON.stringify({ - realm: 'message', - type: 'error', - text: compiler.error - })); - } - } - - return writer.toString(); -} - -function applyList(name, raw) { - const writer = new CompiledListWriter(); - writer.properties.set('name', name); - const compiled = compileList(raw, writer); - const reader = new CompiledListReader(compiled); - staticNetFilteringEngine.fromCompiled(reader); -} - -function enableWASM(path) { - return Promise.all([ - publicSuffixList.enableWASM(`${path}/lib/publicsuffixlist`), - staticNetFilteringEngine.enableWASM(`${path}/js`), - ]); -} - -function pslInit(raw) { - if ( typeof raw !== 'string' || raw.trim() === '' ) { - console.info('Unable to populate public suffix list'); - return; - } - publicSuffixList.parse(raw, punycode.toASCII); - console.info('Public suffix list populated'); -} - -function restart(lists) { - // Remove all filters - reset(); - - if ( Array.isArray(lists) && lists.length !== 0 ) { - // Populate filtering engine with filter lists - for ( const { name, raw } of lists ) { - applyList(name, raw); - } - // Commit changes - staticNetFilteringEngine.freeze(); - staticNetFilteringEngine.optimize(); - } - - return staticNetFilteringEngine; -} - -function reset() { - staticNetFilteringEngine.reset(); -} - -export { - FilteringContext, - enableWASM, - pslInit, - restart, -}; diff --git a/platform/browser/test.html b/platform/browser/test.html deleted file mode 100644 index 32b1aba8e1a2c..0000000000000 --- a/platform/browser/test.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - -uBO Static Network Filtering Engine - - - - - diff --git a/platform/chromium/is-webrtc-supported.html b/platform/chromium/is-webrtc-supported.html index d30b674b1b38d..58238b9469250 100644 --- a/platform/chromium/is-webrtc-supported.html +++ b/platform/chromium/is-webrtc-supported.html @@ -3,7 +3,7 @@ - + diff --git a/platform/chromium/is-webrtc-supported.js b/platform/chromium/is-webrtc-supported.js index 8841370a1050c..263bb686bf99a 100644 --- a/platform/chromium/is-webrtc-supported.js +++ b/platform/chromium/is-webrtc-supported.js @@ -30,11 +30,9 @@ // collected. (function() { - 'use strict'; - - var pc = null; + let pc = null; try { - var PC = self.RTCPeerConnection || self.webkitRTCPeerConnection; + const PC = self.RTCPeerConnection || self.webkitRTCPeerConnection; if ( PC ) { pc = new PC(null); } diff --git a/platform/chromium/manifest.json b/platform/chromium/manifest.json index 637b26764bcdc..0b4095a049bee 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": "93.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..193b7fe6fa0fc 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 @@ -30,6 +26,8 @@ // so we synthetize these missing events when this happens. // https://github.com/uBlockOrigin/uAssets/issues/10323 // Also mind whether the new tab is launched from an external application. +// https://github.com/uBlockOrigin/uBlock-issues/issues/2227 +// Revert commit related to issue above. vAPI.Tabs = class extends vAPI.Tabs { constructor() { @@ -70,8 +68,7 @@ vAPI.Tabs = class extends vAPI.Tabs { const isClientRedirect = Array.isArray(details.transitionQualifiers) && details.transitionQualifiers.includes('client_redirect'); - const isStartPage = details.transitionType === 'start_page'; - if ( isClientRedirect === false && isStartPage === false ) { return; } + if ( isClientRedirect === false ) { return; } this.onCreatedNavigationTargetHandler({ tabId: details.tabId, sourceTabId: details.tabId, @@ -90,71 +87,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 +209,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 ( self.uBO_scriptletsInjected !== undefined ) { 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 { + } + 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..d292341ec3327 100644 --- a/platform/common/vapi-background.js +++ b/platform/common/vapi-background.js @@ -43,9 +43,6 @@ if ( vAPI.canWASM === false ) { vAPI.supportsUserStylesheets = vAPI.webextFlavor.soup.has('user_stylesheet'); -const hasOwnProperty = (o, p) => - Object.prototype.hasOwnProperty.call(o, p); - /******************************************************************************/ vAPI.app = { @@ -190,7 +187,7 @@ vAPI.browserSettings = (( ) => { set: function(details) { for ( const setting in details ) { - if ( hasOwnProperty(details, setting) === false ) { continue; } + if ( Object.hasOwn(details, setting) === false ) { continue; } switch ( setting ) { case 'prefetching': { const enabled = !!details[setting]; @@ -320,7 +317,7 @@ vAPI.Tabs = class { try { result = await webext.tabs.executeScript(...args); } - catch(reason) { + catch { } return Array.isArray(result) ? result : []; } @@ -334,7 +331,7 @@ vAPI.Tabs = class { try { tab = await webext.tabs.get(tabId); } - catch(reason) { + catch { } return tab instanceof Object ? tab : null; } @@ -351,7 +348,7 @@ vAPI.Tabs = class { try { await webext.tabs.insertCSS(...arguments); } - catch(reason) { + catch { } } @@ -360,7 +357,7 @@ vAPI.Tabs = class { try { tabs = await webext.tabs.query(queryInfo); } - catch(reason) { + catch { } return Array.isArray(tabs) ? tabs : []; } @@ -372,7 +369,7 @@ vAPI.Tabs = class { try { await webext.tabs.removeCSS(...arguments); } - catch(reason) { + catch { } } @@ -530,7 +527,7 @@ vAPI.Tabs = class { try { tab = await webext.tabs.update(...arguments); } - catch (reason) { + catch { } return tab instanceof Object ? tab : null; } @@ -556,7 +553,7 @@ vAPI.Tabs = class { try { await webext.tabs.remove(tabId); } - catch (reason) { + catch { } } @@ -569,7 +566,7 @@ vAPI.Tabs = class { { bypassCache: bypassCache === true } ); } - catch (reason) { + catch { } } @@ -668,7 +665,7 @@ if ( webext.windows instanceof Object ) { try { win = await webext.windows.get(...arguments); } - catch (reason) { + catch { } return win instanceof Object ? win : null; }, @@ -677,7 +674,7 @@ if ( webext.windows instanceof Object ) { try { win = await webext.windows.create(...arguments); } - catch (reason) { + catch { } return win instanceof Object ? win : null; }, @@ -686,7 +683,7 @@ if ( webext.windows instanceof Object ) { try { win = await webext.windows.update(...arguments); } - catch (reason) { + catch { } return win instanceof Object ? win : null; }, @@ -702,7 +699,7 @@ if ( webext.browserAction instanceof Object ) { try { await webext.browserAction.setTitle(...arguments); } - catch (reason) { + catch { } }, }; @@ -712,28 +709,28 @@ if ( webext.browserAction instanceof Object ) { try { await webext.browserAction.setBadgeTextColor(...arguments); } - catch (reason) { + catch { } }; vAPI.browserAction.setBadgeBackgroundColor = async function() { try { await webext.browserAction.setBadgeBackgroundColor(...arguments); } - catch (reason) { + catch { } }; vAPI.browserAction.setBadgeText = async function() { try { await webext.browserAction.setBadgeText(...arguments); } - catch (reason) { + catch { } }; vAPI.browserAction.setIcon = async function() { try { await webext.browserAction.setIcon(...arguments); } - catch (reason) { + catch { } }; } @@ -807,7 +804,7 @@ if ( webext.browserAction instanceof Object ) { let data; try { data = ctx.getImageData(0, 0, w, h); - } catch(ex) { + } catch { } return data; }; @@ -958,6 +955,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 @@ -1083,7 +1081,7 @@ vAPI.messaging = { msgId: this.msgId, msg: response !== undefined ? response : null, }); - } catch (ex) { + } catch { this.messaging.onPortDisconnect(this.port); } // Store for reuse @@ -1219,7 +1217,7 @@ vAPI.Net = class { { const wrrt = browser.webRequest.ResourceType; for ( const typeKey in wrrt ) { - if ( hasOwnProperty(wrrt, typeKey) ) { + if ( Object.hasOwn(wrrt, typeKey) ) { this.validTypes.add(wrrt[typeKey]); } } @@ -1381,6 +1379,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; } @@ -1464,7 +1470,7 @@ vAPI.adminStorage = (( ) => { let store; try { store = await webext.storage.managed.get(); - } catch(ex) { + } catch { } vAPI.storage.set({ cachedManagedStorage: store || {} }); }; @@ -1479,7 +1485,7 @@ vAPI.adminStorage = (( ) => { } else { bin = bin.cachedManagedStorage; } - } catch(ex) { + } catch { bin = {}; } cacheManagedStorage(); @@ -1679,7 +1685,7 @@ vAPI.cloud = (( ) => { // operation to fail. try { await deleteChunks(datakey, chunkCount + 1); - } catch (reason) { + } catch { } // Push the data to browser-provided cloud storage. @@ -1733,7 +1739,7 @@ vAPI.cloud = (( ) => { if ( typeof entry === 'string' ) { entry = JSON.parse(entry); } - } catch(_) { + } catch { } return entry; }; @@ -1754,7 +1760,7 @@ vAPI.cloud = (( ) => { webext.storage.sync.getBytesInUse(keys), webext.storage.sync.getBytesInUse(null), ]); - } catch(ex) { + } catch { } if ( Array.isArray(results) === false ) { return; } return { used: results[0], total: results[1], max: QUOTA_BYTES }; diff --git a/platform/common/vapi-client.js b/platform/common/vapi-client.js index a6d46c6259078..afa939d1a73bd 100644 --- a/platform/common/vapi-client.js +++ b/platform/common/vapi-client.js @@ -165,7 +165,7 @@ vAPI.messaging = { } try { this.port = browser.runtime.connect({name: vAPI.sessionId}) || null; - } catch (ex) { + } catch { this.port = null; } // Not having a valid port at this point means the main process is diff --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/dig/snfe.js b/platform/dig/snfe.js index 70908285bf33b..f0b4e55ab2277 100644 --- a/platform/dig/snfe.js +++ b/platform/dig/snfe.js @@ -19,22 +19,12 @@ Home: https://github.com/gorhill/uBlock */ -/* eslint-disable-next-line no-redeclare */ /* globals process */ -'use strict'; - -/******************************************************************************/ - -import { strict as assert } from 'assert'; +import { StaticNetFilteringEngine, enableWASM } from './index.js'; +import { mkdir, readFile, writeFile } from 'fs/promises'; import { createRequire } from 'module'; -import { readFile, writeFile, mkdir } from 'fs/promises'; import { dirname } from 'path'; -import { fileURLToPath } from 'url'; - -const __dirname = dirname(fileURLToPath(import.meta.url)); - -import { enableWASM, StaticNetFilteringEngine } from './index.js'; /******************************************************************************/ diff --git a/platform/firefox/manifest.json b/platform/firefox/manifest.json index aa49d395a9291..888dced282b82 100644 --- a/platform/firefox/manifest.json +++ b/platform/firefox/manifest.json @@ -17,10 +17,10 @@ "browser_specific_settings": { "gecko": { "id": "uBlock0@raymondhill.net", - "strict_min_version": "78.0" + "strict_min_version": "92.0" }, "gecko_android": { - "strict_min_version": "79.0" + "strict_min_version": "92.0" } }, "commands": { @@ -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..a5a80b8d6e34b 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 ( self.uBO_scriptletsInjected !== undefined ) { 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 { + } + 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 { + } + 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/firefox/webext.js b/platform/firefox/webext.js index e9bff76305024..67ad05dd3789e 100644 --- a/platform/firefox/webext.js +++ b/platform/firefox/webext.js @@ -19,6 +19,4 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - export default browser; diff --git a/platform/mv3/README.md b/platform/mv3/README.md index 2400bfe71cffa..2a2fcf01c21bc 100644 --- a/platform/mv3/README.md +++ b/platform/mv3/README.md @@ -7,15 +7,19 @@ The following assumes a linux environment. 1. Open Bash console 2. `git clone https://github.com/gorhill/uBlock.git` 3. `cd uBlock` -4. `make mv3-[platform]`, where `[platform]` is either `chromium` or `firefox` -5. This will fully build uBO Lite, and during the process filter lists will be downloaded from their respective remote servers +4. `git submodule init` +5. `git submodule update` +6. `make mv3-[platform]`, where `[platform]` is either `chromium`, `edge`, `firefox`, or `safari` +7. This will fully build uBO Lite, and during the process filter lists will be downloaded from their respective remote servers Upon completion of the script, the resulting extension package will become present in: - Chromium: `dist/build/uBOLite.chromium` -- Firefox: `dist/build/uBOLite.firefox` +- Edge: `dist/build/uBOLite.edge` +- Firefox: `dist/build/uBOLite.firefox` +- Safari: `dist/build/uBOLite.safari` -The folder `dist/build/mv3-data` will cache data fetched from remote 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. @@ -27,5 +31,4 @@ All the final rulesets are present in the `dist/build/uBOLite.[platform]/ruleset --- -[1] https://github.com/gorhill/uBlock/blob/c4d324362fdb95ff8ef20f0b18f42f0eec955433/tools/make-mv3.sh -[2] https://github.com/gorhill/uBlock/blob/c4d324362fdb95ff8ef20f0b18f42f0eec955433/tools/make-mv3.sh#L103 +[1] https://github.com/gorhill/uBlock/blob/c4d324362fdb95ff8ef20f0b18f42f0eec955433/tools/make-mv3.sh
diff --git a/platform/mv3/chromium/manifest.json b/platform/mv3/chromium/manifest.json index b3e77ccc24ab5..8c21e531a2d4c 100644 --- a/platform/mv3/chromium/manifest.json +++ b/platform/mv3/chromium/manifest.json @@ -12,12 +12,23 @@ "service_worker": "/js/background.js", "type": "module" }, + "commands": { + "enter-zapper-mode": { + "description": "__MSG_zapperTipEnter__" + }, + "enter-picker-mode": { + "description": "__MSG_pickerTipEnter__" + } + }, "declarative_net_request": { "rule_resources": [ ] }, "default_locale": "en", "description": "__MSG_extShortDesc__", + "host_permissions": [ + "" + ], "icons": { "16": "img/icon_16.png", "32": "img/icon_32.png", @@ -25,12 +36,9 @@ "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": [ - "" - ], "permissions": [ "activeTab", "declarativeNetRequest", @@ -42,5 +50,42 @@ "managed_schema": "managed_storage.json" }, "version": "1.0", - "web_accessible_resources": [] + "web_accessible_resources": [ + { + "resources": [ + "/strictblock.html" + ], + "matches": [ + "" + ], + "use_dynamic_url": true + }, + { + "resources": [ + "/zapper-ui.html" + ], + "matches": [ + "" + ], + "use_dynamic_url": true + }, + { + "resources": [ + "/picker-ui.html" + ], + "matches": [ + "" + ], + "use_dynamic_url": true + }, + { + "resources": [ + "/unpicker-ui.html" + ], + "matches": [ + "" + ], + "use_dynamic_url": true + } + ] } diff --git a/platform/mv3/description/en.md b/platform/mv3/description/en.md index 571402469e91a..4f42f797f114f 100644 --- a/platform/mv3/description/en.md +++ b/platform/mv3/description/en.md @@ -1,30 +1,9 @@ ## Description -**uBO Lite** (uBOL), a **permission-less** [MV3 API-based](https://developer.chrome.com/docs/extensions/mv3/intro/) content blocker. +**uBO Lite** (uBOL), an efficient [MV3 API-based](https://developer.chrome.com/docs/extensions/mv3/intro/) content blocker. uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is [performed reliably](https://developer.chrome.com/docs/extensions/reference/scripting/#method-registerContentScripts) by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. -uBOL does not require broad "read/modify data" [permission](https://developer.chrome.com/docs/extensions/mv3/declare_permissions/) at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read/modify data" permissions at install time.
**However, [...]** - uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using declarative cosmetic and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -![uBOL's popup panel: no permission](https://user-images.githubusercontent.com/585534/195468156-d7e63ab9-abfa-443c-a8f6-e646a29b801e.png) - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request: - -![uBOL's popup panel: browser warning](https://user-images.githubusercontent.com/585534/195342593-2b82b740-70a3-4507-a0e5-d7aee803b286.png) - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site: - -![uBOL's popup panel: permissions to inject content](https://user-images.githubusercontent.com/585534/195342612-85d109d9-9006-4eb5-95a5-fec8a4f233ea.png) - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to modify and read data on all websites: - -![uBOL's options: Default filtering mode](https://user-images.githubusercontent.com/585534/195343335-a0aa103e-621e-4137-9bcf-9821dc881be1.png) - -
- The default ruleset corresponds to at least uBlock Origin's default filterset: - uBlock Origin's built-in filter lists @@ -33,9 +12,3 @@ The default ruleset corresponds to at least uBlock Origin's default filterset: - Peter Lowe’s Ad and tracking server list You can add more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff --git a/platform/mv3/description/webstore.ar.txt b/platform/mv3/description/webstore.ar.txt index 97675121f0c9d..459716f83ec6e 100644 --- a/platform/mv3/description/webstore.ar.txt +++ b/platform/mv3/description/webstore.ar.txt @@ -1,4 +1,4 @@ -نسخة مبسطة (uBOL) مانع محتوى من نوع MV3 تجريبي *أقل طلبا للتصاريح* MV3-قاعدة الحظر الأساسية +uBO Lite (uBOL) هو مانع محتوى يعتمد على MV3. تتوافق مجموعة القواعد الافتراضية مع مجموعة عوامل التصفية الافتراضية لـ uBlock Origin: @@ -7,30 +7,6 @@ - الخصوصية السهلة - قائمة خادم الإعلانات والتتبع لبيتر لوي -يمكنك إضافة المزيد من القواعد من خلال زيارة صفحة الخيارات ومن ثم أنقر على رمز _Cogs_ في اللوحة المنبثقة. +يمكنك تفعيل المزيد من مجموعات القواعد من خلال زيارة صفحة الخيارات - انقر على أيقونة _الترس_ في لوحة الإشعارات. -uBOL صريح تمامًا، مما يعني أنه لا تحتاج إلى uBOL بشكل دائم لحدوث تصفية المحتوى، يتم إجراء تصفية المحتوى من خلال إضافة CSS/JS بشكل موثوق به بواسطة المتصفح نفسه بدلًا من الإضافة. - هذا يعني أن uBOL نفسه لا يستهلك موارد وحدة المعالجة المركزية/الذاكرة أثناء استمراره في حظر المحتوى. عملية عامل الخدمة في uBOL مطلوبة _فقط_ عند التفاعل مع اللوحة المنبثقة أو صفحة الخيارات. - -لا يتطلب uBOL صلاحية واسعة «لقراءة البيانات وتعديلها» في وقت التثبيت، وبالتالي فإن قدراته محدودة مقارنة بـ uBlock Origin أو إضافات حظر الإعلانات الأخرى التي تتطلب صلاحية واسعة «قراءة البيانات وتعديلها» في وقت التثبيت. - - -ومع ذلك، يسمح لك uBOL "بوضوح" بمنح صلاحيات موسعة على مواقع محددة من اختيارك حتى يتمكن من التصفية بشكل أفضل على تلك المواقع باستخدام التصفية التجميلية وإضافة النص. - - -لمنح صلاحيات موسعة على موقع معين، افتح اللوحة المنبثقة واختر وضع التصفية إما الأمثل أو الكامل. - -سيحذرك المتصفح من مخاطر منح صلاحيات إضافية التي يطلبها الامتداد على الموقع الحالي، وسيتعين عليك إختيار بما إذا كنت تقبل الطلب أو ترفضه. - - -إذا قبلت طلب uBOL بالحصول على صلاحيات إضافية على الموقع الحالي، فستتمكن من تصفية المحتوى بشكل أفضل للموقع الحالي. - - -بإمكانك اختيار وضع التصفية الافتراضية من خلال صفحة خيارات uBOL. إذا اخترت الوضع الأمثل أو الكامل باعتباره الوضع الافتراضي، فستحتاج إلى منح uBOL الإذن لقراءة البيانات وتعديلها على جميع مواقع الويب. - - -ضع في اعتبارك أن هذا لا يزال عملًا قيد التنفيذ، هذه هي الأهداف النهائية: - -لا يمكنك تحديد الأذونات المستخدمة لاحقًا في التثبيت، تحديدك للأذونات سيكون خلال زيارتك لكل موقع. - -تقريري تمامًا للموثوقية ولكفاءة وحدة المعالجة المركزية/الذاكرة. +uBOL صريح تمامًا، مما يعني أنه لا تحتاج إلى uBOL بشكل دائم لحدوث تصفية المحتوى، يتم إجراء تصفية المحتوى من خلال إضافة CSS/JS بشكل موثوق به بواسطة المتصفح نفسه بدلًا من الإضافة. هذا يعني أن uBOL نفسه لا يستهلك موارد وحدة المعالجة المركزية/الذاكرة أثناء استمراره في حظر المحتوى. diff --git a/platform/mv3/description/webstore.az.txt b/platform/mv3/description/webstore.az.txt index 8ff852cf786a6..502b480308363 100644 --- a/platform/mv3/description/webstore.az.txt +++ b/platform/mv3/description/webstore.az.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) *icazəsiz* MV3 əsaslı məzmun bloklayıcısıdır. +uBO Lite (uBOL) is an MV3-based content blocker. Defolt qaydalar dəsti uBlock Origin-in defolt filtr dəstinə uyğundur: @@ -7,24 +7,6 @@ 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. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff --git a/platform/mv3/description/webstore.be.txt b/platform/mv3/description/webstore.be.txt index d5a2e9812c0df..0c143201a3709 100644 --- a/platform/mv3/description/webstore.be.txt +++ b/platform/mv3/description/webstore.be.txt @@ -1,30 +1,12 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) гэта базаваны на MV3 блакавальнік змесціва. -The default ruleset corresponds to uBlock Origin's default filterset: +Прадвызначаны набор правіл адпавядае тыпавому набору фільтраў uBlock Origin: -- uBlock Origin's built-in filter lists +- Убудаваныя спісы фільтраў uBlock Origin - EasyList - EasyPrivacy -- Peter Lowe’s Ad and tracking server list +- Спіс сервераў з рэкламай і адсочвання ад Peter Lowe -You can 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 does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Цалкам дэкларатыўная ацэнка надзейнасці і эфектыўнасці работы працэсара/памяці. +uBOL цалкам дэкларатыўны, то-бок не мае неабходнасці ў сталым uBOL працэсе дзеля фільтрацыі, а фільтрацыя змесціва на аснове інʼекцыі CSS/JS надзейна выконваецца пераважна самім браўзерам замест пашырэння. Гэта значыць, што uBOL не спажывае рэсурсаў працэсара/памяці пры блакаванні зместу -- службовы працэс uBOL патрэбны _толькі_ падчас узаемадзеяння з усплывальнай панэллю або наладамі. diff --git a/platform/mv3/description/webstore.bg.txt b/platform/mv3/description/webstore.bg.txt index 6e58550d3cf46..3c21dcde5c36c 100644 --- a/platform/mv3/description/webstore.bg.txt +++ b/platform/mv3/description/webstore.bg.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) е блокер за съдържание *без разрешения*, базиран на MV3. +uBO Lite (uBOL) е блокер за съдържание, базиран на MV3. Наборът от правила по подразбиране съответства на набора от филтри по подразбиране на uBlock Origin: @@ -7,24 +7,6 @@ uBO Lite (uBOL) е блокер за съдържание *без разреше - EasyPrivacy - Списък със сървъри на Peter Lowe за реклами и проследяване -Можете да добавите още набори от правила, като посетите страницата с опции – щракнете върху иконата _зъбно колело_ в изскачащия панел. +Можете да включите още набори от правила, като посетите страницата с опции – щракнете върху иконата „зъбно колело“ в изскачащия панел. uBOL е изцяло декларативен, което означава, че няма нужда от постоянен процес на uBOL за филтриране, а филтрирането на съдържание, базирано на инжектиране на CSS/JS, се извършва надеждно от самия браузър, а не от разширението. Това означава, че самият uBOL не консумира ресурси на процесора/паметта, докато тече блокирането на съдържанието – работният процес на услугата на uBOL е необходим _само_ когато взаимодействате с изскачащия панел или страниците с опции. - -uBOL не изисква широко разрешение за "четене и промяна на данни" по време на инсталиране, поради което възможностите му са ограничени в сравнение с uBlock Origin или други блокери на съдържание, изискващи широко разрешение за "четене и промяна на данни" по време на инсталиране. - -Въпреки това uBOL ви позволява да предоставите *изрично* разширени разрешения за определени сайтове по ваш избор, за да може да филтрира по-добре тези сайтове, като използва козметично филтриране и инжектиране на скриптове. - -За да предоставите разширени разрешения за даден сайт, отворете изскачащия панел и изберете по-висок режим на филтриране, например Оптимален или Пълен. - -След това браузърът ще ви предупреди за последиците от предоставянето на допълнителните разрешения, поискани от разширението, за текущия сайт и ще трябва да кажете на браузъра дали приемате или отхвърляте искането. - -Ако приемете искането на uBOL за допълнителни разрешения за текущия сайт, той ще може да филтрира по-добре съдържанието на текущия сайт. - -Можете да зададете режима на филтриране по подразбиране от страницата с опции на uBOL. Ако изберете оптимален или пълен режим по подразбиране, ще трябва да предоставите на uBOL разрешение за четене и промяна на данни във всички уебсайтове. - -Имайте предвид, че това все още е в процес на разработка с тези крайни цели: - -- По време на инсталацията няма широки разрешения за хоста – разширените разрешения се предоставят изрично от потребителя за всеки сайт. - -- Изцяло декларативен за надеждност и ефективност на процесора/паметта. diff --git a/platform/mv3/description/webstore.bn.txt b/platform/mv3/description/webstore.bn.txt index 83e739a19aebb..0850a419f9649 100644 --- a/platform/mv3/description/webstore.bn.txt +++ b/platform/mv3/description/webstore.bn.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) হল একটি *অনুমতি-হীন* MV3-ভিত্তিক কন্টেন্ট ব্লকার। +uBO Lite (uBOL) হলো একটি ম্যানিফেস্ট ভার্সন ৩ ভিত্তিক কনটেন্ট ব্লকার পূর্ব নির্ধারিত নিয়ম সেট uBlock অরিজিনের ডিফল্ট ফিল্টারসেটের সাথে মিলে যায়: @@ -7,24 +7,6 @@ uBO Lite (uBOL) হল একটি *অনুমতি-হীন* MV3-ভিত - সহজ গোপনীয়তা - পিটার লো এর বিজ্ঞাপন এবং ট্র্যাকিং সার্ভার তালিকা -আপনি অপশন পেজে গিয়ে আরও নিয়ম সেট যোগ করতে পারেন -- পপআপ প্যানেলে _Cogs_ আইকনে ক্লিক করুন। +তুমি অপশন পাতায় গিয়ে আরও নিয়ম যোগ করতে পারো -- পপআপ প্যানেলে _গিয়ার_ আইকনে ক্লিক করে। uBOL সম্পূর্ণরূপে ঘোষণামূলক, অর্থাৎ ফিল্টারিং করতে একটি স্থায়ী uBOL প্রক্রিয়ার প্রয়োজন নেই, এবং CSS/JS ইনজেকশন-ভিত্তিক বিষয়বস্তু ফিল্টারিং এক্সটেনশনের পরিবর্তে ব্রাউজার নিজেই নির্ভরযোগ্যভাবে এই কাজ করে থাকে। এর মানে হল যে কন্টেন্ট ব্লকিং চলমান থাকা অবস্থায় uBOL নিজেই CPU/মেমরি রিসোর্স ব্যবহার করে না -- uBOL-এর পরিষেবার প্রক্রিয়ার প্রয়োজন শুধুমাত্র_ যখন আপনি পপআপ প্যানেল বা অপশন পেজগুলির সাথে ইন্টারঅ্যাক্ট করেন। - -uBOL-এর ইন্সটল করার সময় বিস্তৃত "পড়ার ও ডেটা পরিবর্তন করার" অনুমতির প্রয়োজন হয় না, তাই ইউব্লক অরিজিন বা অন্যান্য কনটেন্ট ব্লকের তুলনায় এটির সীমিত ক্ষমতা বাক্সের বাইরে রয়েছে যার জন্য ইন্সটল করার সময় বিস্তৃত "ডেটা পড়ুন এবং পরিবর্তন করুন" অনুমতি প্রয়োজন। - -যাইহোক, uBOL আপনাকে আপনার পছন্দের নির্দিষ্ট সাইটে *স্পষ্টভাবে* বর্ধিত অনুমতি প্রদান করে যাতে এটি কসমেটিক ফিল্টারিং এবং স্ক্রিপ্টলেট ইনজেকশন ব্যবহার করে সেই সাইটগুলিতে আরও ভাল ফিল্টার করতে পারে। - -একটি সাইটে বর্ধিত অনুমতি প্রদানের জন্য, পপআপ প্যানেল খুলুন এবং একটি উচ্চতর ফিল্টারিং মোড বাছাই করুন যেমন অপটিমাল বা কমপ্লিট। - -ব্রাউজারটি তখন বর্তমান সাইটে এক্সটেনশন দ্বারা অনুরোধ করা অতিরিক্ত অনুমতি প্রদানের প্রভাব সম্পর্কে আপনাকে সতর্ক করবে এবং আপনি অনুরোধটি গ্রহণ করবেন বা প্রত্যাখ্যান করবেন কিনা তা আপনার ব্রাউজারকে বলতে হবে। - -আপনি যদি বর্তমান সাইটে অতিরিক্ত অনুমতির জন্য uBOL-এর অনুরোধ গ্রহণ করেন, তাহলে এটি বর্তমান সাইটের জন্য আরও ভালভাবে ফিল্টার করতে সক্ষম হবে। - -আপনি uBOL এর বিকল্প পৃষ্ঠা থেকে ডিফল্ট ফিল্টারিং মোড সেট করতে পারেন। আপনি যদি অপটিমাল বা কমপ্লিট মোডটিকে ডিফল্ট হিসেবে বেছে নেন, তাহলে আপনাকে uBOL-কে সমস্ত ওয়েবসাইটের ডেটা পড়তে এবং পরিবর্তন করার অনুমতি দিতে হবে। - -মনে রাখবেন এই শেষ লক্ষ্যগুলির ফলাফলের সাথে এখনও সংস্করণ কাজ চলছে: - -- ইনস্টল করার সময় কোনও বিস্তৃত অনুমতি নেই -- বর্ধিত অনুমতিগুলি প্রতি-সাইট ভিত্তিতে ব্যবহারকারীর দ্বারা স্পষ্টভাবে প্র্রদান করা হয়। - -- নির্ভরযোগ্যতা এবং CPU/মেমরি দক্ষতার জন্য সম্পূর্ণরূপে পূর্বঘোষণামুূলক। diff --git a/platform/mv3/description/webstore.br_FR.txt b/platform/mv3/description/webstore.br_FR.txt index 03354935ec791..1a0465f7a7f8e 100644 --- a/platform/mv3/description/webstore.br_FR.txt +++ b/platform/mv3/description/webstore.br_FR.txt @@ -1,30 +1,12 @@ -uBO Lite (uBOL) zo ur stanker noazadurioù *hep aotre rekis ebet* diazezet war ar manifesto MV3. +uBO Lite (uBOL) zo ur stanker noazadurioù diazezet war ar manifesto MV3. Ar reolennoù dre ziouer a glot gant silañ dre ziouer uBlock Origin: - Rolloù siloù genidik a uBlock Origin - EasyList - EasyPrivacy -- Peter Lowe’s Ad and tracking server list +- Roll ar servijerioù brudañ ha heuliañ eus Peter Lowe Tu zo deoc'h ouzhpennañ reolennoù all en arventennoù -- klikit war an ikon _kendentadur_ er banell popup. -uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -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. - -Ma asantit da reiñ muioc'h a aotreoù da uBOL war ar bajenn-mañ e vo silet gwelloc'h. - -Gallout a rit termeniñ ar mod silañ dre ziouer e pajenn arventennoù uBOL. Ma tibabit ar mod Gwellañ pe an hini Klok evel ar mod dre ziouer e vo ret deoc'h aotren uBOL da lenn ha kemmañ roadennoù en holl lec'hiennoù. - -Dalc'hit soñj ez eo uBOL ur raktres war ober c'hoazh hag a zo e bal: - -- 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. +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ù. diff --git a/platform/mv3/description/webstore.bs.txt b/platform/mv3/description/webstore.bs.txt index 96ba7d2ef9c3b..46be783042d65 100644 --- a/platform/mv3/description/webstore.bs.txt +++ b/platform/mv3/description/webstore.bs.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) je blokator sadržaja zasnovan na MV3 *bez dozvole*. +uBO Lite (uBOL) is an MV3-based content blocker. Zadani skup pravila odgovara zadanom skupu filtera uBlock Origin: @@ -7,24 +7,6 @@ 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. - -uBOL ne zahtijeva široku dozvolu za "čitanje i modificiranje podataka" u vrijeme instalacije, stoga su njegove ograničene mogućnosti izvan kutije u poređenju sa uBlock Origin-om ili drugim blokatorima sadržaja koji zahtijevaju široke dozvole za "čitanje i modificiranje podataka" u vrijeme instalacije. - -Međutim, uBOL vam omogućava da *eksplicitno* dodijelite proširene dozvole na određenim web lokacijama po vašem izboru kako bi mogao bolje filtrirati te stranice koristeći kozmetičko filtriranje i injekcije skriptleta. - -Da biste dali proširene dozvole za datu web lokaciju, otvorite iskačući panel i odaberite viši način filtriranja kao što je Optimal ili Complete. - -Pregledač će vas tada upozoriti na efekte odobravanja dodatnih dozvola koje ekstenzija traži na trenutnoj web stranici, a vi ćete morati reći pretraživaču da li prihvatate ili odbijate zahtjev. - -Ako prihvatite uBOL-ov zahtjev za dodatnim dozvolama na trenutnoj stranici, moći će bolje filtrirati sadržaj za trenutnu stranicu. - -Možete postaviti zadani način filtriranja sa uBOL-ove stranice sa opcijama. Ako odaberete Optimal ili Kompletan način kao zadani, morat ćete dati uBOL-u dozvolu da čita i mijenja podatke na svim web stranicama. - -Imajte na umu da je ovo još uvijek u toku, sa ovim krajnjim ciljevima: - -- Nema širokih dozvola za host u vrijeme instalacije - proširene dozvole se eksplicitno dodeljuju od strane korisnika na bazi po lokaciji. - -- Potpuno deklarativno za pouzdanost i efikasnost CPU/memorije. diff --git a/platform/mv3/description/webstore.ca.txt b/platform/mv3/description/webstore.ca.txt index e75025530597a..e65272d84eb45 100644 --- a/platform/mv3/description/webstore.ca.txt +++ b/platform/mv3/description/webstore.ca.txt @@ -1,4 +1,4 @@ -L'uBO Lite (uBOL) és un blocador de contingut *sense permisos* basat en MV3. +L'uBO Lite (uBOL) és un blocador de contingut basat en MV3. El conjunt de regles per defecte correspon al conjunt de filtres per defecte d'uBlock Origin: @@ -7,26 +7,8 @@ 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. - -L'uBOL no requereix un ampli permís de "lectura i modificació de dades" en el moment de la instal·lació, per tant, les seves capacitats limitades en comparació amb l'uBlock Origin o altres blocadors de contingut que requereixen amplis permisos de "lectura i modificació de dades" en el moment de la instal·lació. - -Tanmateix, l'uBOL us permet concedir *explícitament* permisos ampliats en llocs específics que trieu perquè pugui filtrar millor en aquests llocs mitjançant filtres cosmètics i injeccions de scriptlet. - -Per concedir permisos ampliats en un lloc determinat, obriu el tauler emergent i seleccioneu un mode de filtrat superior, com ara Òptim o Complet. - -Aleshores, el navegador us avisarà sobre els efectes de la concessió dels permisos addicionals sol·licitats per l'extensió al lloc actual, i haureu d'indicar-li al navegador si accepteu o rebutgeu la sol·licitud. - -Si accepteu la sol·licitud d'uBOL de permisos addicionals al lloc actual, podrà filtrar millor el contingut del lloc actual. - -Podeu establir el mode de filtratge per defecte des de la pàgina d'opcions d'uBOL. Si trieu el mode Òptim o Complet per defecte, haureu de concedir a l'uBOL el permís per llegir i modificar dades a tots els llocs web. - -Tingueu en compte que encara és un treball en curs, amb aquests objectius finals: - -- No hi ha permisos d'amfitrió amplis en el moment de la instal·lació; els permisos ampliats els concedeix explícitament l'usuari per lloc. - -- Totalment declaratiu per a la fiabilitat i l'eficiència de la CPU/memòria. diff --git a/platform/mv3/description/webstore.cs.txt b/platform/mv3/description/webstore.cs.txt index 05ca248f754a1..97d87722c20dc 100644 --- a/platform/mv3/description/webstore.cs.txt +++ b/platform/mv3/description/webstore.cs.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) je blokovač obsahu vyžadující méně oprávnění, založený na MV3. +uBO Lite (uBOL) je blokovač obsahu založený na MV3. Výchozí sada pravidel koresponduje k výchozím sadám filtrů uBlock Origin: @@ -7,24 +7,6 @@ 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í. - -uBOL nevyžaduje rozsáhlá oprávnění ke "čtení a úpravě dat" v době instalace, a proto má ihned po instalaci omezené možnosti ve srovnání s uBlock Origin nebo jinými blokovači obsahu, které vyžadují rozsáhlá oprávnění ke "čtení a úpravě dat" v době instalace. - -Nicméně, uBOL vám umožňuje *explicitně* udělit rozšířená oprávnění na konkrétních webech podle vašeho výběru, aby mohl na těchto webech lépe filtrovat pomocí kosmetického filtrování a vstřikování skriptů. - -Chcete-li na daném webu udělit rozšířená oprávnění, otevřete vyskakovací panel a vyberte vyšší režim filtrování, například optimální nebo kompletní. - -Prohlížeč vás poté upozorní na důsledky udělení dalších oprávnění požadovaných rozšířením na aktuálním webu a vy budete muset prohlížeči sdělit, zda žádost přijímáte nebo odmítáte. - -Pokud přijmete žádost uBOL o další oprávnění na aktuálním webu, bude moci lépe filtrovat obsah aktuálního webu. - -Výchozí filtrovací režim můžete nastavit na stránce nastavení uBOL. Pokud jako výchozí zvolíte režim optimální nebo kompletní, budete muset uBOL udělit oprávnění ke čtení a úpravě dat na všech webových stránkách. - -Mějte na paměti, že toto je stále nedokončená práce s těmito konečnými cíli: - -- Žádná rozsáhlá oprávnění hostitele v době instalace -- rozšířená oprávnění uděluje explicitně uživatel na jednotlivých stránkách. - -- Zcela deklarativní pro spolehlivost a efektivitu CPU/paměti. diff --git a/platform/mv3/description/webstore.cv.txt b/platform/mv3/description/webstore.cv.txt index e03fa801ee7f0..ef089202b9565 100644 --- a/platform/mv3/description/webstore.cv.txt +++ b/platform/mv3/description/webstore.cv.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -7,24 +7,6 @@ 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 does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff --git a/platform/mv3/description/webstore.cy.txt b/platform/mv3/description/webstore.cy.txt index e03fa801ee7f0..056c49a64ca7d 100644 --- a/platform/mv3/description/webstore.cy.txt +++ b/platform/mv3/description/webstore.cy.txt @@ -1,30 +1,12 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. -The default ruleset corresponds to uBlock Origin's default filterset: +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. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff --git a/platform/mv3/description/webstore.da.txt b/platform/mv3/description/webstore.da.txt index 1d3218873cb5a..cbb28b901cea5 100644 --- a/platform/mv3/description/webstore.da.txt +++ b/platform/mv3/description/webstore.da.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) er en *tilladelsesløs* MV3-baseret indholdsblocker. +uBO Lite (uBOL) er en MV3-baseret indholdsblocker. Standardregelsættet svarer til uBlock Origins standardfiltersæt: @@ -7,24 +7,6 @@ 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. - -uBOL kræver ikke en omfattende "læse og ændre data" tilladelse under installationen, derfor dens begrænsede egenskaber fra start af sammenlignet med uBlock Origin eller andre indholdsblockere, som kræver omfattende "læse/ændre data" tilladelser under installationen. - -uBOL giver dog mulighed for *eksplicit* at tildele udvidede tilladelser på bestemte websteder efter eget valg, så den bedre kan filtrere på disse websteder vha. kosmetisk filtrering og scriptlet-injektioner. - -For at tildele udvidede tilladelser på et givent websted, åbn pop op-panelet og vælg en højere filtreringstilstand, såsom Optimal eller Komplet. - -Browseren advarer derefter om virkningerne af de ekstra tildelte tilladelser, som udvidelsen anmoder om på det aktuelle websted, og man vil skulle fortælle browseren, hvorvidt anmodningen accepteres eller afslås. - -Accepteres uBOLs anmodning om ekstra tilladelser på det aktuelle websted, vil den bedre kunne filtrere indhold på webstedet. - -Standardfiltreringstilstanden kan angives via uBOLs indstillingsside. Hvis tilstanden Optimal eller Komplet vælges som standardtilstand, skal uBOL tildeles tilladelse til at læse og ændre data på alle websteder. - -Husk dog, at dette stadig er et igangværende arbejde med disse slutmål: - -- Ingen omfattende værtstilladelser under installationen -- udvidede tilladelser tildeles eksplicit af brugeren på webstedsbasis. - -- Fuldstændig deklarativ for pålidelighed og CPU-/hukommelseseffektivitet. diff --git a/platform/mv3/description/webstore.de.txt b/platform/mv3/description/webstore.de.txt index 807ec84c1d918..9dac25a87abbb 100644 --- a/platform/mv3/description/webstore.de.txt +++ b/platform/mv3/description/webstore.de.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) ist ein Inhaltsblocker, der *ohne Berechtigungen* auskommt und auf MV3 basiert. +uBO Lite (uBOL) ist ein MV3-basierter Inhaltsblocker. Die Standardregeln entsprechen den Standardfiltern von uBlock Origin: @@ -7,24 +7,6 @@ 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. - -uBOL erfordert bei der Installation keine weitreichende Berechtigung zum Lesen und Ändern von Daten, daher sind die Möglichkeiten im Vergleich zu uBlock Origin oder anderen Inhaltsblockern, die bei der Installation weitreichende Berechtigungen zum Lesen und Ändern von Daten erfordern, von vornherein begrenzt. - -Allerdings können Sie mit uBOL *explizit* erweiterte Berechtigungen für bestimmte Websites Ihrer Wahl erteilen, sodass diese Websites durch kosmetisches Filtern und Scriptlet-Injektionen besser gefiltert werden können. - -Um erweiterte Berechtigungen für eine bestimmte Website zu erteilen, öffnen Sie das Pop-up-Fenster und wählen Sie einen stärkeren Filtermodus wie »Optimal« oder »Vollständig«. - -Der Browser warnt Sie anschließend über die Auswirkungen der zusätzlichen Berechtigungen, die von der Erweiterung für die aktuelle Website angefordert werden, und Sie können entscheiden, ob Sie zustimmen oder ablehnen. - -Wenn Sie die Anfrage von uBOL nach zusätzlichen Berechtigungen für die aktuelle Website zustimmen, kann uBOL die Inhalte für die aktuelle Website besser filtern. - -Sie können den Standardfiltermodus in den Optionen von uBOL festlegen. Wenn Sie den Modus »Optimal« oder »Vollständig« als Standardmodus wählen, müssen Sie uBOL die Berechtigung erteilen, Daten auf allen Websites lesen und ändern zu dürfen. - -Denken Sie daran, dass sich dieses Projekt noch in Entwicklung befindet und folgende Ziele verfolgt: - -- Keine weitreichenden Host-Berechtigungen bei der Installation — erweiterte Berechtigungen werden explizit von Ihnen für jede einzelne Website erteilt. - -- Vollständig deklarativ für Zuverlässigkeit und CPU-/Speichereffizienz. diff --git a/platform/mv3/description/webstore.el.txt b/platform/mv3/description/webstore.el.txt index 32d043db89b31..50b2449776486 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,24 +7,6 @@ - EasyPrivacy - Peter Lowe’s Ad and tracking server list -Μπορείτε να προσθέσετε περισσότερα σύνολα κανόνων μεταβαίνοντας στη σελίδα επιλογών -- κάντε κλικ στο εικονίδιο _Cogs_ στον αναδυόμενο πίνακα. +Μπορείτε να προσθέσετε περισσότερα σύνολα κανόνων από τη σελίδα επιλογών -- κάντε κλικ στο εικονίδιο _γρανάζι_ στον αναδυόμενο πίνακα. Το uBOL είναι εξ'ολοκλήρου δηλωτικό, πράγμα που σημαίνει ότι δεν υπάρχει ανάγκη για μόνιμη διαδικασία uBOL για να πραγματοποιηθεί το φιλτράρισμα, και το φιλτράρισμα περιεχομένου που βασίζεται σε έγχυση CSS/JS εκτελείται αξιόπιστα από το ίδιο το πρόγραμμα περιήγησης και όχι από την επέκταση. Αυτό σημαίνει ότι το ίδιο το uBOL δεν καταναλώνει πόρους CPU/μνήμης ενώ ο αποκλεισμός περιεχομένου είναι σε εξέλιξη -- η διαδικασία του service worker του uBOL απαιτείται _μόνο_ όταν αλληλεπιδράτε με τον αναδυόμενο πίνακα ή τις σελίδες επιλογών. - -Το uBOL δεν απαιτεί ευρεία άδεια "ανάγνωσης και τροποποίησης δεδομένων" κατά τον χρόνο εγκατάστασης, επομένως έχει εξαρχής περιορισμένες δυνατότητές σε σύγκριση με το uBlock Origin ή άλλα προγράμματα αποκλεισμού περιεχομένου που απαιτούν ευρείες άδειες "ανάγνωσης/τροποποίησης δεδομένων" κατά την εγκατάσταση. - -Ωστόσο, το uBOL σάς επιτρέπει *ρητά* να εκχωρείτε εκτεταμένες άδειες σε συγκεκριμένους ιστότοπους της επιλογής σας, ώστε να μπορεί να φιλτράρει καλύτερα σε αυτούς τους ιστότοπους χρησιμοποιώντας κοσμητικό φιλτράρισμα και έγχυση scriptlet. - -Για να εκχωρήσετε εκτεταμένα δικαιώματα σε έναν δεδομένο ιστότοπο, ανοίξτε το αναδυόμενο πλαίσιο και επιλέξτε μια υψηλότερη λειτουργία φιλτραρίσματος, όπως Βέλτιστη ή Ολοκληρωμένη. - -Στη συνέχεια, το πρόγραμμα περιήγησης θα σας προειδοποιήσει για τα αποτελέσματα της χορήγησης των πρόσθετων δικαιωμάτων που ζητούνται από την επέκταση στον τρέχοντα ιστότοπο και θα πρέπει να ενημερώσετε το πρόγραμμα περιήγησης εάν αποδέχεστε ή απορρίπτετε το αίτημα. - -Εάν αποδεχτείτε το αίτημα του uBOL για πρόσθετα δικαιώματα στον τρέχοντα ιστότοπο, θα μπορεί να φιλτράρει καλύτερα το περιεχόμενο για τον τρέχοντα ιστότοπο. - -Μπορείτε να ορίσετε την προεπιλεγμένη λειτουργία φιλτραρίσματος από τη σελίδα επιλογών του uBOL. Εάν επιλέξετε τη λειτουργία Βέλτιστη ή Ολοκληρωμένη ως προεπιλεγμένη, θα πρέπει να εκχωρήσετε στην uBOL την άδεια ανάγνωσης και τροποποίησης δεδομένων σε όλους τους ιστότοπους. - -Λάβετε υπόψη ότι αυτό είναι ακόμη ένα έργο σε εξέλιξη, με αυτούς τους τελικούς στόχους: - -- Να μην υπάρχουν ευρείες άδειες hosts κατά την εγκατάσταση -- οι εκτεταμένες άδειες παραχωρούνται ρητά από τον χρήστη σε βάση ανά τοποθεσία. - -- Εντελώς δηλωτικό για αξιοπιστία και απόδοση CPU/μνήμης. diff --git a/platform/mv3/description/webstore.en_GB.txt b/platform/mv3/description/webstore.en_GB.txt index e03fa801ee7f0..ef089202b9565 100644 --- a/platform/mv3/description/webstore.en_GB.txt +++ b/platform/mv3/description/webstore.en_GB.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -7,24 +7,6 @@ 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 does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff --git a/platform/mv3/description/webstore.eo.txt b/platform/mv3/description/webstore.eo.txt index e03fa801ee7f0..ef089202b9565 100644 --- a/platform/mv3/description/webstore.eo.txt +++ b/platform/mv3/description/webstore.eo.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -7,24 +7,6 @@ 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 does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff --git a/platform/mv3/description/webstore.es.txt b/platform/mv3/description/webstore.es.txt index 2ea6cfff29121..8d7e3cca0e37c 100644 --- a/platform/mv3/description/webstore.es.txt +++ b/platform/mv3/description/webstore.es.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) es un bloqueador de contenido con *menos permisos* basado en MV3. +uBO Lite (uBOL) es un bloqueador de contenido basado en MV3. Por defecto ya trae configuradas las siguientes listas de filtros: @@ -7,24 +7,6 @@ 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. - -uBOL no requiere amplios permisos para "leer y modificar datos" en el momento de la instalación, de ahí sus capacidades limitadas en comparación con uBlock Origin u otros bloqueadores de contenido que requieren amplios permisos para "leer y modificar datos" en el momento de la instalación. - -Sin embargo, uBOL te permite otorgar *explícitamente* permisos extendidos en sitios específicos de tu elección para que pueda filtrar mejor en esos sitios usando filtrado cosmético e inyecciones de scriptlet. - -Para otorgar permisos extendidos en un sitio determinado, abre el panel emergente y elige un modo de filtrado superior, como óptimo o completo. - -Después el navegador te advertirá sobre los efectos de otorgar los permisos adicionales solicitados por la extensión en el sitio actual, y deberás indicar al navegador si aceptas o rechazas la solicitud. - -Si aceptas la solicitud de uBOL para permisos adicionales en el sitio actual, será capaz de filtrar mejor el contenido para el sitio actual. - -Puedes establecer el modo de filtrado predeterminado desde la página de opciones de uBOL. Si eliges como predeterminado el modo óptimo o completo, tendrás que otorgar a uBOL el permiso para leer y modificar datos en todos los sitios web. - -Téngase en cuenta que esto todavía es un trabajo en progreso, con estos objetivos finales: - -- Sin amplios permisos de host en el momento de la instalación, los permisos ampliados son otorgados explícitamente por el usuario en cada sitio. - -- Completamente declarativo para confiabilidad y eficiencia de la CPU/memoria. diff --git a/platform/mv3/description/webstore.et.txt b/platform/mv3/description/webstore.et.txt index 520e4ce134edc..7a1f4fc3ad2e5 100644 --- a/platform/mv3/description/webstore.et.txt +++ b/platform/mv3/description/webstore.et.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) on MV3-l põhinev *lubadeta* sisutõkestaja. +uBO Lite (uBOL) on MV3-l põhinev sisutõkestaja. Tavaline reeglitekogum vastab uBlock Origini tavalisele filtritekogumile: @@ -7,24 +7,6 @@ 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. - -uBOL ei nõua paigaldamise ajal teadatuntud andmete lugemise ja muutmise luba, seega võrreldes seda nõudva laiendusega uBlock Origin või muu sisutõkestiga on uBOL-i piiratus üks selle funktsioonidest. - -Kuid uBOL võimaldab *selgesõnaliselt* anda täpsemaid lubasid teie valitud veebilehtedele, et neid saaks paremini filtreerida ilufiltrite ja skriptisüstidega. - -Veebilehele täpsustatud lubade andmiseks ava hüpikpaneel ja vali põhjalikum filtreerimisrežiim, näiteks Optimaalne või Põhjalik. - -Seejärel hoiatab veebilehitseja praeguse veebilehe laienduse taotletud täiendavate õiguste andmise tagajärgede eest ja peate veebilehitsejale ütlema, kas nõustute taotlusega või keeldute sellest. - -Kui nõustute uBOLi taotlusega täiendavate õiguste saamiseks praegusel veebilehel, saab see praeguse veebilehe sisu paremini filtreerida. - -Fltreerimise tavarežiimi saate määrata uBOLi valikute lehelt. Kui määrate optimaalse või põhjaliku režiimi tavaliseks, peate andma uBOLile loa kõikide veebilehtede andmete lugemiseks ja muutmiseks. - -Pidage meeles, et see on veel arendamisel, mille lõppeesmärgid on järgmised: - -- Paigaldamise ajal laialdased hostiõigused puuduvad – kasutaja annab laiendatud load selgesõnaliselt ja veebilehe põhiselt. - -- Täiesti deklaratiivne töökindluse ja protsessori/mälu tõhususe osas. diff --git a/platform/mv3/description/webstore.eu.txt b/platform/mv3/description/webstore.eu.txt index a15101de8214a..f2373f6895b53 100644 --- a/platform/mv3/description/webstore.eu.txt +++ b/platform/mv3/description/webstore.eu.txt @@ -1,30 +1,12 @@ -uBO Lite (uBOL) irakargarri blokeatzailea de, baimen gutxiekin eta MV3ean basatua +uBO Lite (uBOL) is an MV3-based content blocker. -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 does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -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. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. +uBOL 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. diff --git a/platform/mv3/description/webstore.fa.txt b/platform/mv3/description/webstore.fa.txt index e03fa801ee7f0..c455fdc90983a 100644 --- a/platform/mv3/description/webstore.fa.txt +++ b/platform/mv3/description/webstore.fa.txt @@ -1,30 +1,12 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. -The default ruleset corresponds to uBlock Origin's default filterset: +مجموعه قوانین پیش فرض آن مطابق با مجموعه قوانین پیش فرض 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. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff --git a/platform/mv3/description/webstore.fi.txt b/platform/mv3/description/webstore.fi.txt index 7e5693c715911..a5784b1df14c8 100644 --- a/platform/mv3/description/webstore.fi.txt +++ b/platform/mv3/description/webstore.fi.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) on *käyttöoikeudeton* MV3-pohjainen sisällönestotyökalu. +uBO Lite (uBOL) on MV3-pohjainen sisällönestotyökalu. Oletusarvoiset sääntömääritykset vastaavat uBlock Origin -laajennuksen oletuksia: @@ -7,24 +7,6 @@ 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ä. - -uBOL ei edellytä laajan tietojen luku- ja muokkausoikeuden myöntämistä asennuksen yhteydessä, jonka vuoksi sen oletusarvoiset valmiudet ovat uBlock Originia ja muita vastaavia sisällönestotyökaluja rajallisemmat. - -On kuitenkin mahdollista myöntää *yksinomaisesti* uBOL:lle laajennetut käyttöoikeudet sivustokohtaisesti niiden suodatuksen tehostamiseksi kosmeettisella suodatuksella ja scriplet-injektoinnilla. - -Laajemmat oikeudet myönnetään avoimelle sivustolle avaamalla ponnahduspaneeli ja valitsemalla korkeampi suodatustaso, kuten Optimaalinen tai Täysi. - -Tällöin selain varoittaa laajennuksen avoimelle sivustolle pyytämien käyttöoikeuksien seurauksista ja pyytää hyväksymään tai hylkäämään pyynnön. - -Jos uBOL:n käyttöoikeuspyyntö avoimelle sivustolle hyväksytään, se pystyy suodattamaan sivuston sisältöä tehokkaammin. - -Voit asettaa oletusarvoisen suodatustilan uBOL:n asetussivulta. Jos valitset oletustilaksi Optimaalinen tai Täysi, on uBOL:lle myönnettävä oikeus lukea ja muokata tietojasi kaikilla verkkosivustoilla. - -Huomioithan, että laajennuksen kehitys vielä kesken, seuraavilla tavoitteilla: - -- Laajoja käyttöoikeuksia ei tarvita asennusvaiheesssa, vaan laajennetut oikeudet myönnetään aina sivustokohtaisesti käyttäjän toimesta. - -- Täysin deklaratiivinen luotettavuutta ja prosessorin/muistin kuormituksen keventämiseksi. diff --git a/platform/mv3/description/webstore.fil.txt b/platform/mv3/description/webstore.fil.txt index 0bb5710c6e233..7da60386564c1 100644 --- a/platform/mv3/description/webstore.fil.txt +++ b/platform/mv3/description/webstore.fil.txt @@ -1,4 +1,4 @@ -Ang uBO Lite (uBOL) ay isang eksperimental at *permission-less* na tagaharang ng content na nakabase sa MV3. +Isang content blocker na nakabase sa MV3 ang uBO Lite (uBOL). Tulad ng uBlock Origin, ito rin ang mga default na listahan ng mga filter: @@ -7,24 +7,6 @@ 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. +Maaring magpagana ng mas maraming ruleset sa page ng options -- pindutin ang _Cogs_ sa popup na panel. Deklaratibo lamang ang uBOL, kaya hindi nito kailangan ng permanenteng proseso upang mag-filter, at mainam na ginagawa ng browser mismo imbes na ekstensyon ang pagfi-filter sa content na nakabase sa CSS o JS. Ibig-sabihin, hindi kumokonsyumo ng CPU o memorya ang uBOL habang nanghaharang -- ang proseso ng trabahante ng serbisyo ay kailangan _lang_ kung nasa popup panel o pahina ng opsyon ka. - -Hindi kailangan ng uBOL ang malawakang pahintulot para "basahin at baguhin ang data" pagka-install, kaya kung bago pa lang itong install ay limitado ang kakayahan nito kumpara sa uBlock Origin o iba pang mga pangharang ng content na nangangailangan ng malawakang pahintulot para "basahin at baguhin ang data" pagka-install. - -Ngunit, pwede mong *pasadyang* pahintulutan ang uBOL na magkaroon ng pinalawak na pahintulot sa mga website na pipiliin mo para mas mapabuti ang pagfi-filter sa mga site na iyon gamit ang kosmetikong pagfi-filter at injeksyon ng scriptlet. - -Upang bigyan ito ng pinalawak na pahintulot sa isang site, buksan ang popup panel at pumili ng isang mode sa pagfi-filter tulad ng Pinainam o Kumpleto. - -Babalaan ka ng browser tungkol sa mga epekto ng pagbibigay ng karagdagang pahintulot na hinihiling ng ekstensyon sa kasalukuyang site, at kailangan mong tumugon kung pinapahintulutan mo ba ito o hindi. - -Kung tatanggapin mo ang hiling ng uBOL para sa karagdagang mga pahintulot sa kasalukuyang site, mas magiging mainam ang pagfi-filter nito sa content para sa kasalukuyang site. - -Maitatakda mo ang default na mode sa pagfi-filter sa pahina ng mga opsyon ng uBOL. Kailangan mong pahintulutan ang uBOL na basahin o baguhin ang datos sa lahat ng mga website kung pipiliin mo ang Pinainam o Kumpleto bilang default na mode sa pagfi-filter. - -Tandaang kasalukuyan pang binubuo ang ekstensyong ito, at nilalayon nitong: - -- Walang kakailanganing malawakang pahintulot pagka-install -- ibibigay lang ng user ang karagdagang pahintulot sa mga piling site. - -- Deklaratibo lamang upang maging mapagkakatiwalaan at matipid sa CPU at memorya. diff --git a/platform/mv3/description/webstore.fr.txt b/platform/mv3/description/webstore.fr.txt index 12b9d01d1f4f8..a446e77620cae 100644 --- a/platform/mv3/description/webstore.fr.txt +++ b/platform/mv3/description/webstore.fr.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) est un bloqueur de contenu *sans permission* basé sur le manifeste MV3. +uBO Lite (uBOL) est un bloqueur de contenu basé sur le manifeste MV3. Les règles par défaut correspondent au filtrage par défaut d'uBlock Origin : @@ -7,24 +7,6 @@ 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. - -Contrairement à uBlock Origin ou d'autres extensions de blocage, uBOL ne nécessite pas de larges permissions de "lecture/modification des données" au moment de l'installation, ce qui explique ses capacités au départ limitées. - -Cependant, uBOL vous permet *explicitement* d'accorder des permissions étendues sur les sites Web de votre choix, pour qu'elle puisse mieux les filtrer en utilisant le filtrage esthétique et des injections de scriptlet. - -Pour accorder des permissions étendues sur un site Web donné, ouvrez le panneau pop-up et choisissez un mode de filtrage plus élevé comme le mode Optimal ou le mode Complet. - -Le navigateur vous préviendra alors des effets de l'accord de permissions additionnelles requises par l'extension sur le site Web en cours de consultation et vous devrez indiquer votre choix au navigateur (Accepter/Refuser). - -Si vous acceptez la requête d'uBOL pour des permissions additionnelles sur le site Web en cours de consultation, le filtrage de son contenu sera renforcé. - -Vous pouvez définir le mode de filtrage par défaut depuis la page des paramètres d'uBOL. Si vous choisissez le mode Optimal ou Complet en tant que mode par défaut, vous devrez accorder à uBOL l'autorisation de lire et de modifier des données sur tous les sites Web. - -Gardez à l'esprit que c'est en cours de développement, avec comme objectifs : - -- De ne pas accorder de permissions globales au moment de l'installation -- les permissions étendues s'accordent explicitement par l'utilisateur site par site. - -- De travailler de manière entièrement déclarative pour la fiabilité et l'efficacité processeur/mémoire. diff --git a/platform/mv3/description/webstore.fy.txt b/platform/mv3/description/webstore.fy.txt index 63fa94a819b56..3aaa4d3adcafc 100644 --- a/platform/mv3/description/webstore.fy.txt +++ b/platform/mv3/description/webstore.fy.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is in *tastimmingsleaze* MV3-basearre ynhâldsblokkearder. +uBO Lite (uBOL) is in MV3-basearre ynhâldsblokkearder. De standert regelset komt oerien mei de standert filterset fan uBlock Origin: @@ -7,24 +7,6 @@ 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. - -uBOL fereasket gjin brede tastimming foar it ‘lêzen en oanpassen fan gegevens’ wylst ynstallaasje, fan dêr de beheinde ynboude mooglikheden dêrfan yn fergeliking mei uBlock Origin of oare ynhâldsblokkearders dy’t brede tastimmingen foar it ‘lêzen en oanpassen fan gegevens’ fereaskje wylst de ynstallaasje. - -Jo kinne yn uBOL echter *eksplisyt* wiidweidige tastimmingen ferliene op bepaalde websites fan jo kar, sadat it op dy websites better filterje kin fia kosmetyske filtering en scriptlet-ynjeksjes. - -Om wiidweidige tastimmingen op in bepaalde website te ferlienen, iepenje jo it pop-uppaniel en kieze jo in hegere filtermodus, lykas Optimaal of Folslein. - -De browser warskôget jo dan oer de gefolgen fan it ferlienen fan de troch de útwreiding oanfrege oanfoljende tastimmingen op de aktuele website, en jo moatte de browser witte litte oft jo de oanfraach akseptearje of wegerje. - -As jo de oanfraach fan uBOL foar oanfoljende tastimmingen op de aktuele website akseptearje, sil it ynhâld foar de aktuele website better filterje kinne. - -Jo kinne de standert filtermodus ynstelle fan de opsjesside fan uBOL ôf. As jo de modus Optimaal of Folslein as de standertmodus kieze, moatte jo uBOL de tastimming foar it lêzen en oanpassen fan gegevens op alle websites te ferlienen. - -Unthâld dat dit noch wurk yn útfiering is, mei dizze eindoelen: - -- Gjin brede host-tastimmingen wylst ynstallaasje – wiidweidige tastimmingen wurde eksplisyt en per website ferliend troch de brûker. - -- Folslein deklaratyf omwille fan betrouberheid en CPU-/ûnthâldeffisjinsje. diff --git a/platform/mv3/description/webstore.gl.txt b/platform/mv3/description/webstore.gl.txt index a82432f3762c8..5acb8b794f005 100644 --- a/platform/mv3/description/webstore.gl.txt +++ b/platform/mv3/description/webstore.gl.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) é un bloqueador de contido baseado en MV3 *sen permisos. +uBO Lite (uBOL) é un bloqueador de contido baseado en MV3. O conxunto de regras predeterminado corresponde ao conxunto de filtros predeterminado de uBlock Origin: @@ -7,24 +7,6 @@ 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. - -uBOL non require amplos permisos de "ler e modificar datos" no momento da instalación, de aí as súas capacidades limitadas fóra da caixa en comparación con uBlock Origin ou outros bloqueadores de contido que requiren amplos permisos de "ler e modificar datos" no momento da instalación. - -Non obstante, uBOL permítelle *de forma explícita* conceder permisos estendidos en sitios específicos da súa elección para que poida filtrar mellor neses sitios mediante filtrado cosmético e inxeccións de scriptlet. - -Para conceder permisos estendidos nun sitio determinado, abra o panel emerxente e escolle un modo de filtrado superior, como Óptimo ou Completa. - -A continuación, o navegador avisará sobre os efectos da concesión dos permisos adicionais solicitados pola extensión no sitio actual, e terá que indicarlle ao navegador se acepta ou rexeita a solicitude. - -Se aceptas a solicitude de uBOL de permisos adicionais no sitio actual, poderá filtrar mellor o contido do sitio actual. - -Podes establecer o modo de filtrado predeterminado desde a páxina de opcións de uBOL. Se escolle o modo Óptimo ou Completo como o predeterminado, terá que conceder a uBOL o permiso para ler e modificar datos en todos os sitios web. - -Teña en conta que este aínda é un traballo en curso, cos seguintes obxectivos finais: - -- Non hai permisos de host amplos no momento da instalación. Os permisos estendidos son concedidos explícitamente polo usuario por cada sitio. - -- Totalmente declarativo para a fiabilidade e a eficiencia da CPU/memoria. diff --git a/platform/mv3/description/webstore.gu.txt b/platform/mv3/description/webstore.gu.txt index e03fa801ee7f0..ef089202b9565 100644 --- a/platform/mv3/description/webstore.gu.txt +++ b/platform/mv3/description/webstore.gu.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -7,24 +7,6 @@ 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 does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff --git a/platform/mv3/description/webstore.he.txt b/platform/mv3/description/webstore.he.txt index d931b3dae4271..dc075b3c8abb3 100644 --- a/platform/mv3/description/webstore.he.txt +++ b/platform/mv3/description/webstore.he.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) הוא חוסם תוכן *ללא הרשאות* מבוסס MV3. +uBO Lite (uBOL) is an MV3-based content blocker. ערכת הכללים ברירת מחדל שמתכתבת עם ערכת המסננים של uBlock Origin: @@ -7,24 +7,6 @@ uBO Lite (uBOL) הוא חוסם תוכן *ללא הרשאות* מבוסס MV3. - EasyPrivacy - רשימת שרתי מודעות ומעקב של פיטר לואו -ניתן להוסיף ערכות כללים נוספות מעמוד האפשרויות –על ידי הקשה על סמל _Cogs_ בלוח הצץ. +ניתן לאפשר קבוצות חוקים נוספות בדף האפשרויות - עם לחיצה על סמליל _גלגלי השיניים_ בחלונית הקופצת. uBOL הוא הכרזתי לחלוטין, כלומר אין צורך בתהליך uBOL קבוע כדי שהסינון יתרחש, וסינון תוכן מבוסס הזרקת CSS/JS מבוצע באופן אמין על ידי הדפדפן עצמו ולא על ידי ההרחבה. המשמעות היא ש־uBOL עצמו לא צורכך משאבי מעבד/זיכרון בזמן שחסימת התוכן מתרחשת – תהליך ה־service worker של uBOL נדרש _אך ורק_ בזמן הידוד עם החלון הקופץ או עם עמוד האפשרויות. - -uBOL לא דורש הרשאת "קריאה ושינוי נתונים" נרחבות במהלך ההתקנה, לכן היכולות המוגבלות שלה הישר מהקופסה בהשוואה ל־uBlock Origin או חוסמי תוכן אחרים הדורשים הרשאות "קריאה ושינוי נתונים" נרחבות כבר בזמן ההתקנה. - -עם זאת, uBOL מאפשר להעניק *באופן מפורש* הרשאות נרחבות לאתרים מסויימים על פי בחירה, למיטוב הסינון באתרים אלה, באמצעות סינון קוסמטי והזרקות סקריפלטים. - -כדי להעניק הרשאות נרחבות באתר נתון, נא לפתוח את הלוח הקופץ ולבחור באופן סינון גבוה יותר כגון מיטבי או מלא. - -לאחר מכן, תוצג אזהרת דפדפן על השפעות מתן הרשאות נוספות אותן מבקשת ההרחה באתר הנוכחי, הדפדפן ימתין לקבלת תשובה האם לקבל או לדוחות את בקשת ההרשאה. - -אם תקבל את הבקשה של uBOL להרשאות נוספות באתר הנוכחי, הוא יוכל לסנן טוב יותר תוכן עבור האתר הנוכחי. - -ניתן להגדיר את מצב הסינון המוגדר כברירת מחדל מדף האפשרויות של uBOL. אם הבחירה היתה באופןסינון מיטבי או מלא כברירת המחדל, יידרש להעניק ל־uBOL הרשאת קריאה שנוי נתונים בכל אתרי הרשת. - -יש לזכור שזו עדיין 'עבודה בתהליך', עם המטרות הבאות: - -- אין הרשאות מארח רחבות בזמן ההתקנה -- הרשאות מורחבות מוענקות במפורש על ידי המשתמש על בסיס לכל אתר. - -הכרזתי לחלוטין, אמין ויעיל בצריכת משאבי מעבד/זיכרון. diff --git a/platform/mv3/description/webstore.hi.txt b/platform/mv3/description/webstore.hi.txt index 7b361bc8c5bed..97d13b48f030a 100644 --- a/platform/mv3/description/webstore.hi.txt +++ b/platform/mv3/description/webstore.hi.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) एक *अनुमति-रहित* MV3-आधारित कन्टेन्ट ब्लॉकर है। +uBO Lite (uBOL) is an MV3-based content blocker. डिफ़ॉल्ट रूलसेट uBlock Origin के डिफ़ॉल्ट फ़िल्टर सेट के अनुरूप होता है: @@ -7,24 +7,6 @@ uBO Lite (uBOL) एक *अनुमति-रहित* MV3-आधारित - EasyPrivacy - Peter Lowe की विज्ञापन एवं ट्रैकिंग सर्वर सू‍ची -आप विकल्प पृष्ठ पर जाकर और अधिक रूलसेट जोड़ सकते हैं -- पॉपअप पैनल में _Cogs_ आइकन पर क्लिक करें। +आप विकल्प पृष्ठ पर जाकर और अधिक नियम-सेट सक्षम कर सकते हैं -- पॉपअप पैनल में _Cogs_ आइकन पर क्लिक करें। uBOL पूरी तरह से वर्णनात्मक है, जिसका यह अर्थ है कि फ़िल्टरिंग के लिए एक स्थायी uBOL प्रक्रिया की कोई आवश्यकता नहीं है, और CSS/JS इंजेक्शन-आधारित कन्टेन्ट फ़िल्टरिंग एक्सटेंशन के बजाय ब्राउज़र द्वारा विश्वसनीय रूप से की जाती है। इसका यह अर्थ है कि कन्टेन्ट ब्लॉक करते समय uBOL द्वारा सीपीयू/मेमोरी संसाधनों का उपभोग स्वयं नहीं किया जाता है -- uBOL की सर्विस प्रोसेस की आवश्यकता _केवल_ तब होती है जब आप पॉपअप पैनल या विकल्प पृष्ठों पर कोई अंत:क्रिया करते हैं। - -uBOL को इन्सटॉल करते समय "डेटा को पढ़ने और संशोधित करने" की व्यापक अनुमति की आवश्यकता नहीं होती है, अतः इसकी सीमित क्षमताओं तत्काल उपयोगिता की तुलना में uBlock Origin या अन्य कन्टेन्ट ब्लॉकर को इन्सटॉलेशन के समय "डेटा को पढ़ने और संशोधित करने" की व्यापक अनुमतियों की आवश्यकता होती है। - -हालांकि, uBOL आपको अपनी मनपसंद विशिष्ट साइटों पर विस्तारित अनुमतियां देना *स्पष्ट रूप से* अनुमत करता है ताकि यह कॉस्मेटिक फ़िल्टरिंग और स्क्रिप्टलेट इंजेक्शन का उपयोग करके उन साइटों पर अच्छी तरह से फ़िल्टर कर सके। - -किसी एक साइट पर विस्तारित अनुमतियां देने के लिए, पॉपअप पैनल खोलें और उच्च फ़िल्टरिंग मोड, जैसे कि 'अनुकूलतम' (ऑप्टिमल) या 'पूर्ण' (कंपलीट) चुनें। - -इसके बाद ब्राउज़र द्वारा आपको वर्तमान साइट पर एक्सटेंशन द्वारा अनुरोधित अतिरिक्त अनुमतियों को देने के प्रभावों के बारे में चेतावनी दी जाएगी, और आपको ब्राउज़र को यह बताना होगा कि आप अनुरोध को स्वीकार करते हैं या अस्वीकार करते हैं। - -यदि आप वर्तमान साइट पर अतिरिक्त अनुमतियों के लिए uBOL के अनुरोध को स्वीकार करते हैं, तो यह वर्तमान साइट के लिए कन्टेन्ट अच्छी तरह से फ़िल्टर करने में सक्षम होगा। - -आप uBOL के विकल्प पृष्ठ से डिफ़ॉल्ट फ़िल्टरिंग मोड को सेट कर सकते हैं। यदि आप 'अनुकूलतम' (ऑप्टिमल) या 'पूर्ण' (कंपलीट) मोड को डिफ़ॉल्ट रूप से चुनते हैं, तो आपको uBOL को सभी वेबसाइटों पर डेटा को पढ़ने और संशोधित करने के लिए अनुमत करना होगा। - -ध्यान रखें कि यह कार्य अभी भी प्रगतिधीन है, और इसके न‍िम्नांकित अंतिम लक्ष्यों तय किये गए हैं: - -- इन्सटॉल करते समय कोई व्यापक होस्ट अनुमतियां नहीं -- विस्तारित अनुमतियां उपयोगकर्ता द्वारा हर एक साइट के आधार पर स्पष्ट रूप से दी जाती हैं। - -- विश्वसनीयता और सीपीयू/मेमोरी दक्षता के लिए पूरी तरह वर्णनात्मक। diff --git a/platform/mv3/description/webstore.hr.txt b/platform/mv3/description/webstore.hr.txt index 898bc2002f3f0..0fe0ef4a41fb6 100644 --- a/platform/mv3/description/webstore.hr.txt +++ b/platform/mv3/description/webstore.hr.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) je bloker sadržaja *bez dopuštenja* baziran na MV3. +uBO Lite (uBOL) je bloker sadržaja baziran na MV3. Zadana lista pravila odgovara uBlock Origin-ovoj zadanoj listi filtera: @@ -7,24 +7,6 @@ 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. - -uBOL ne zahtijeva široku dozvolu za "čitanje i izmjenu podataka" u vrijeme instalacije, stoga ima zadane ograničene mogućnosti u usporedbi s uBlock Origin ili drugim blokatorima sadržaja koji zahtijevaju veću dozvolu za "čitanje i izmjenu podataka" u vrijeme instalacije. - -Međutim, uBOL vam omogućuje da *eksplicitno* dodijelite proširena dopuštenja na određenim web-stranicama po vašem izboru tako da može bolje filtrirati te web-stranice koristeći kozmetičko filtriranje i injekcijske skripte. - -Da biste dodijelili proširena dopuštenja na određenoj web stranici, otvorite skočnu ploču i odaberite viši način filtriranja kao što je Optimalno ili Potpuno. - -Preglednik će vas tada upozoriti o učincima dodjele dodatnih dopuštenja koje traži ekstenzija na trenutnom mjestu, a vi ćete morati reći pregledniku prihvaćate li ili odbijate zahtjev. - -Ako prihvatite uBOL-ov zahtjev za dodatnim dozvolama na trenutnoj stranici, moći će bolje filtrirati sadržaj na njoj. - -Zadani način filtriranja možete postaviti na stranici s opcijama uBOL-a. Ako kao zadano odaberete Optimalni ili Potpuni način rada, morati ćete dati uBOL-u dopuštenje za čitanje i izmjenu podataka na svim web stranicama. - -Imajte na umu da je ovo još u tijeku, sa sljedećim krajnjim ciljevima: - -- Nema širokih dopuštenja hosta u vrijeme instalacije -- proširena dopuštenja izričito dodjeljuje korisnik za svaku pojedinačnu stranicu. - -- Potpuno deklarativno za pouzdanost i učinkovitost CPU/memorije. diff --git a/platform/mv3/description/webstore.hu.txt b/platform/mv3/description/webstore.hu.txt index 4d54e2f1f1aa5..a07bcc27a80f7 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,24 +7,6 @@ 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. - -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. - -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. - -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. - -A böngésző ekkor figyelmezteti Önt a bővítmény által kért további engedélyek megadásának hatásaira az aktuális webhelyen, és közölnie kell a böngészővel, hogy elfogadja-e vagy elutasítja a kérést. - -Ha elfogadja az uBOL további engedélyekre vonatkozó kérését az aktuális webhelyen, akkor jobban tudja szűrni az aktuális webhely tartalmát. - -Az alapértelmezett szűrési módot az uBOL beállítási oldalán állíthatja be. Ha az Optimális vagy a Teljes módot választja alapértelmezettként, akkor az uBOL-nak engedélyt kell adnia az adatok olvasására és módosítására az összes webhelyen. - -Ne feledje, hogy ez még folyamatban van, 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. - -- Teljesen deklaratív a nagyobb megbízhatóság illetve CPU- és memóriahatékonyság érdekében. +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. diff --git a/platform/mv3/description/webstore.hy.txt b/platform/mv3/description/webstore.hy.txt index c847ac69df042..75522194eb932 100644 --- a/platform/mv3/description/webstore.hy.txt +++ b/platform/mv3/description/webstore.hy.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL)-ը բովանդակության արգելափակիչ է, որը *չի պահանջում թույլտվություններ*, և հիմնված է MV3-ի վրա։ +uBO Lite (uBOL) is an MV3-based content blocker. Կանոնների լռելյայն փաթեթը համապատասխանում է uBlock Origin-ի լռելյայն զտիչների փաթեթին։ @@ -7,28 +7,6 @@ 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 աշխատանքային գործընթացն աշխատում է _միայն_ երբ Դուք փոփոխություններ եք կատարում դուրս լողացող վահանակում կամ ընտրանքների էջում։ - -uBOL-ը տեղադրման ժամանակ «տվյելները լիովին ընթերցելու և փոփոխելու» թույլտվություն չի պահանջում, ուստի այն ունի սահմանափակ հնարավորություններ՝ համեմատած uBlock Origin-ի և բովանդակության այլ արգելափակիչների հետ, որոնք տեղադրման ժամանակ պահանջում են այդպիսի թույլտվություն։ - -Однако uBOL позволяет *намеренно* давать расширенные разрешения для определенных сайтов - по вашему усмотрению, чтобы эффективнее работать, используя косметическую фильтрацию и scriptlet-внедрения. - -Այնուամենայնիվ, uBOL-ը թույլ է տալիս *դիտմամբ* տրամադրել ընդլայնված թույլտվություններ Ձեր ընտրած կայքերի համար, որպեսզի այն կարողանա էլ ավելի լավ զտել այդ կայքերը՝ օգտագործելով կոսմետիկ զտումը և սցենարների արմատավորումները։ - -Для предоставления расширенных разрешений на текущем сайте - откройте всплывающую панель и выберите повышенный режим фильтрации: Оптимальный или Полный. - -Ընթացիկ կայքում ընդլայնված թույլտվություններ տրամադրելու համար բացեք դուրս լողացող վահանակը և ընտրեք ընդլայնված զտման ռեժիմ՝ Գերադասելի կամ Ամբողջական։ - -Այնուհետև զննիչը կզգուշացնի Ձեզ ընթացիկ կայքում ընդլայնման կողմից պահանջվող լրացուցիչ թույլտվությունների տրամադրման հետևանքների մասին, և Դուք պետք է ընտրեք՝ ընդունում եք, թե մերժում եք հայտը։ - -Եթե ​​ընդունեք uBOL-ին լրացուցիչ թույլտվություններ տալու հայտը, ապա այն կկարողանա ավելի արդյունավետ կերպով զտել ընթացիկ կայքի բովանդակությունը։ - -Դուք կարող եք սահմանել զտման լռելյայն ռեժիմը uBOL-ի ընտրանքների էջում։ Եթե ​​որպես լռելյայն ընտրեք «Գերադասելի» կամ «Ամբողջական» ռեժիմը, պետք կլինի uBOL-ին թույլտվություն տրամադրեք կարդալու և փոփոխելու տվյալները բոլոր կայքերում։ - -Հիշեք, որ այս նախագիծը մշակման ակտիվ փուլում է, որ ունի հետևյալ նպատակները. - -- Տեղադրման ընթացքում Սահմանափակ թույլտվություններով աշխատանք տեղադրման ժամանակ. օգտվողը ընդլայնված թույլտվություններ է տալիս իր հայեցողությամբ, յուրաքանչյուր կայքի համար առանձին։ - -- Ամբողջովին դեկլարատիվ է հուսալիության և մշակիչի/հիշողության արտադրողականության համար։ diff --git a/platform/mv3/description/webstore.id.txt b/platform/mv3/description/webstore.id.txt index 33c86b66979cc..27f5a944fcf8c 100644 --- a/platform/mv3/description/webstore.id.txt +++ b/platform/mv3/description/webstore.id.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) adalah pemblokir konten berbasis MV3 yang membutuhkan lebih sedikit perizinan. +uBO Lite (uBOL) adalah pemblokir konten berbasis MV3. Kumpulan aturan bawaan sesuai dengan kumpulan penyaringan bawaan uBlock Origin: @@ -7,24 +7,6 @@ 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 rangkaian aturan dengan mengunjungi halaman opsi -- klik ikon _Cogs_ di panel popup. -uBOL sepenuhnya deklaratif, yang mana tidak membutuhkan proses permanen uBOL agar penyaringan dapat terjadi, dan penyaringan konten berbasis injeksi CSS/JS dilakukan sepenuhnya oleh peramban itu sendiri ketimbang oleh ekstensi. Ini berarti bahwa uBOL sendiri tidak mengkonsumsi sumber daya CPU/memori selama melakukan pemblokiran konten -- proses pekerja layanan uBOL dibutuhkan _hanya_ ketika Anda berinteraksi dengan panel popup atau opsi halaman. - -uBOL tidak membutuhkan izin "baca dan modifikasi data" pada waktu penginstalan, maka kemampuannya lebih terbatas jika dibandingkan dengan uBlock Origin atau pemblokir konten lain yang memerlukan izin "baca dan modifikasi data" pada waktu penginstalan. - -Namun, uBOL memberi anda opsi untuk *secara eksplisit* memberikan izin tambahan pada situs pilihan Anda, sehingga dapat memfilter situs tersebut dengan lebih baik menggunakan pemfilteran kosmetik dan injeksi scriptlet. - -Untuk memberikan izin tambahan pada situs tertentu, buka panel popup dan pilih mode pemfilteran yang lebih tinggi seperti Optimal atau Complete. - -Perambaan kemudian akan memperingatkan anda tentang efek memberikan izin tambahan yang diminta oleh ekstensi pada situs saat ini, dan Anda harus memberitahu perambaan apakah anda menyetujui atau menolak permintaan. - -Jika Anda menyetujui permintaan uBOL untuk izin tambahan pada situs terkini, uBOL akan dapat menyaring konten dengan lebih baik untuk situs terkini. - -Anda dapat menentukan mode penyaringan bawaan dari halaman pengaturan uBOL Jika Anda memilih mode Optimal atau Complete sebagai mode bawaan, Anda perlu memberikan uBOL izin untuk membaca dan mengubah data pada semua situs web. - -Mohon diingat bahwa ini msaih dalam tahap proses pengerjaan, dengan tujuan akhir sebagai berikut: - -- Tidak ada izin pengguna yang luas saat penginstalan -- izin tambahan diberikan secara eksplisit oleh pengguna berdasarkan tiap situs. - -- Sepenuhnya delkaratif untuk reliabilitas dan CPU/efisiensi memori. +uBOL sepenuhnya bersifat deklaratif, artinya tidak diperlukan proses uBOL permanen agar penyaringan dapat terjadi, dan penyaringan konten berbasis injeksi CSS/JS dilakukan secara andal oleh browser itu sendiri dan bukan oleh ekstensi. Artinya uBOL sendiri tidak mengonsumsi sumber daya CPU/memori saat pemblokiran konten sedang berlangsung -- proses pekerja layanan uBOL diperlukan _hanya_ saat Anda berinteraksi dengan panel popup atau halaman opsi. diff --git a/platform/mv3/description/webstore.it.txt b/platform/mv3/description/webstore.it.txt index 0aa86f4f846a6..26b2cc119ef12 100644 --- a/platform/mv3/description/webstore.it.txt +++ b/platform/mv3/description/webstore.it.txt @@ -1,30 +1,12 @@ -uBO Lite (uBOL) è un sistema per bloccare contenuti che *non richiede autorizzazioni* basato su MV3. +uBO Lite (uBOL) è un sistema di blocco dei contenuti basato su MV3. -L'insieme di regole 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 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. - -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. - -Se accetti la richiesta di uBOL per ulteriori autorizzazioni sul sito corrente, sarà in grado di filtrare meglio i contenuti 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. - -- Interamente dichiarativo per l'affidabilità e l'efficienza della CPU/memoria. +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. diff --git a/platform/mv3/description/webstore.ja.txt b/platform/mv3/description/webstore.ja.txt index 5ae015f74dd89..59ac0888610b6 100644 --- a/platform/mv3/description/webstore.ja.txt +++ b/platform/mv3/description/webstore.ja.txt @@ -1,30 +1,12 @@ -uBO Lite (uBOL) は権限を必要としない MV3 ベースのコンテンツブロッカーです。 +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の追加的な権限要求リクエストを承認すると、そのサイトへのコンテンツフィルタリングの品質をあげることができます。 - -uBOL の設定ページで既定のフィルタリングモードを設定できます。 「最適」または「完全」を規定のフィルタリング モードに設定した場合、すべてのWebサイトで「データの読み取りと変更」権限を付与する必要があります。 - -注意として、uBOL はまだ開発途中で、これらの開発目標があります。 - -- インストール時に広範なホスト権限は不要 -- 拡張された権限はサイトごとにユーザーによって明示的に付与されます。 - -- 完全に宣言的で、CPU、メモリの効率性が良い diff --git a/platform/mv3/description/webstore.ka.txt b/platform/mv3/description/webstore.ka.txt index ffcc9851bd291..0cb4db880e111 100644 --- a/platform/mv3/description/webstore.ka.txt +++ b/platform/mv3/description/webstore.ka.txt @@ -1,30 +1,12 @@ -uBO Lite (uBOL) *ნებართვებისგან თავისუფალი* MV3-ზე დაფუძნებული შიგთავსის შემზღუდავია. +uBO Lite (uBOL) შიგთავსის შემზღუდავია MV3-ის მიხედვით. წესების ნაგულისხმევი კრებული იგივეა, რასაც uBlock Origin იყენებს: -- uBlock Origin – ფილტრების ჩაშენებული სიები +- ჩაშენებული ფილტრებით, uBlock Origin რომ იყენებს - EasyList - EasyPrivacy - Peter Lowe – სარეკლამო სერვერების სია -შეგიძლიათ სხვა კრებულებიც დაამატეთ პარამეტრების გვერდიდან -- დაწკაპეთ _Cogs_ ხატულაზე ამომხტომ არეში. +შეგიძლიათ სხვა კრებულებიც აამოქმედოთ პარამეტრების გვერდიდან -- დაწკაპეთ _Cogs_ ხატულაზე ამომხტომ არეში. -uBOL სრულად დეკლარაციულია, ანუ არაა საჭირო მუდმივად იყოს გაშვებული uBOL-პროცესი გასაფილტრად, CSS/JS ჩანაცვლებით შიგთავსის გაფილტვრას თავად ბრაუზერი უზრუნველყოფს ნაცვლად გაფართოებისა, რაც მეტად საიმედოა. შესაბამისად, uBOL თავად არ დატვირთავს პროცესორს/ოპერატიულს შიგთავსის შეზღუდვის დროს -- uBOL-ის შუამავალი მომსახურე პროცესი საჭიროა _მხოლოდ_ მაშინ, როცა ამომხტომ არესთან ურთიერთქმედებთ ან ცვლით პარამეტრებს. - -uBOL არ საჭიროებს „მონაცემთა წაკითხვისა და შეცვლის“ სრულ ნებართვას დაყენებისას, ვინაიდან მოკვეცილი შესაძლებლობებითაა წარმოდგენილი uBlock Origin-თან ან რეკლამის სხვა შემზღუდავებთან შედარებით, რომლებიც ერთბაშად ითხოვს „მონაცემთა წაკითხვისა და შეცვლის“ უფლებას დაყენებისთანავე. - -ამასთანავე, uBOL საშუალებას გაძლევთ *მკაფიო* თანხმობით მიუთითოთ გაფართოებული ნებართვები ცალკეულ საიტებზე სურვილისამებრ, რომ უკეთ შეიზღუდოს შიგთავსი ხილული ელემენტების გაფილტვრითა და პროგრამული ჩამატებებით. - -გაფართოებული ნებართვების მისაცემად მითითებულ საიტზე, გახსენით ამომხტომი არე და აირჩიეთ ფილტრაციის უფრო მაღალი დონე, როგორიცაა „წონასწორული“ ან „სრული“. - -შემდეგ ბრაუზერი გაგაფრთხილებთ გაფართოების მიერ დამატებითი ნებართვების მოთხოვნის შესახებ მოცემულ საიტზე და აირჩევთ, დათანხმდებით თუ უარყოფთ მოთხოვნას. - -თუ დათანხმდებით uBOL-ს მოთხოვნას დამატებითი ნებართვებისთვის მიმდინარე საიტზე, უკეთ შეძლებს შიგთავსის შეზღუდვას აღნიშნულ საიტზე. - -შეგიძლიათ მიუთითოთ გაფილტვრის ნაგულისხმევი რეჟიმი uBOL-ის პარამეტრების გვერდიდან. თუ აირჩევთ „წონასწორულ“ ან „სრულ“ რეჟიმს ნაგულისხმევად, uBOL-ს უნდა დართოთ ყველა საიტზე მონაცემთა წაკითხვისა და შეცვლის ნება. - -დაიხსომეთ, რომ ჯერ კიდევ მუშავდება შემდეგი მიზნებისთვის: - -- არანაირი სრული ნებართვების ერთბაშად მოთხოვნა დაყენებისას -- დამატებითი უფლებები შეიძლება მიეცეს მომხმარებლის მკაფიო თანხმობით თითოეულ საიტზე ცალ-ცალკე. - -- სრულად დეკლარაციულია პროცესორის/მეხსიერების დასაზოგად. +uBOL მოქმედებს სრულად დადგენილი წესებით, შესაბამისად, არ ესაჭიროება მუდმივად გაშვებული uBOL-პროცესი გასაფილტრად, ხოლო როცა შიგთავსის შეზღუდვა ითხოვს ჩანაცვლდეს CSS/JS, ამას თავად ბრაუზერი უზრუნველყოფს საიმედო გზით, ნაცვლად გაფართოებისა. აქედან გამომდინარე, uBOL თავად არ მოიხმარს პროცესორს/მეხსიერებას შიგთავსის შეზღუდვისას -- uBOL საჭიროებს შუამავალ მომსახურე პროცესს _მხოლოდ_ მაშინ, როცა ამომხტომ არესთან ურთიერთქმედებთ ან ცვლით პარამეტრებს. diff --git a/platform/mv3/description/webstore.kk.txt b/platform/mv3/description/webstore.kk.txt index e03fa801ee7f0..ef089202b9565 100644 --- a/platform/mv3/description/webstore.kk.txt +++ b/platform/mv3/description/webstore.kk.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -7,24 +7,6 @@ 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 does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff --git a/platform/mv3/description/webstore.kn.txt b/platform/mv3/description/webstore.kn.txt index e03fa801ee7f0..da1d83d7965ed 100644 --- a/platform/mv3/description/webstore.kn.txt +++ b/platform/mv3/description/webstore.kn.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -7,24 +7,6 @@ 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 does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. +uBOL 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 ನ ಸೇವಾ ವರ್ಕರ್ ಪ್ರಕ್ರಿಯೆಯು _ಮಾತ್ರಾ_ ಅಗತ್ಯವಿದೆ. diff --git a/platform/mv3/description/webstore.ko.txt b/platform/mv3/description/webstore.ko.txt index c23291c36032e..98c8a3f801056 100644 --- a/platform/mv3/description/webstore.ko.txt +++ b/platform/mv3/description/webstore.ko.txt @@ -1,4 +1,4 @@ -uBO Lite(uBOL)는 *적은 권한을 요구하는* MV3 기반 콘텐츠 차단기입니다. +uBO Lite (uBOL)는 MV3 기반 콘텐츠 차단기입니다. 기본 규칙 목록은 uBlock Origin의 기본 필터 목록과 대응됩니다. @@ -7,24 +7,6 @@ uBO Lite(uBOL)는 *적은 권한을 요구하는* MV3 기반 콘텐츠 차단기 - EasyPrivacy - Peter Lowe’s Ad and tracking server list -설정 페이지에서 규칙 목록을 더욱 추가할 수 있습니다. 팝업 창의 _Cogs_ 아이콘을 누르세요. +설정 페이지에서 규칙 목록을 더 활성화할 수 있습니다. 팝업 창의 _Cogs_ 아이콘을 누르세요. uBOL은 완전히 선언적이라 필터링 중 영구적으로 실행되는 uBOL 프로세스를 필요로 하지 않으며, CSS/JS 주입 기반 콘텐츠 필터링이 확장 프로그램이 아닌 브라우저 자체에서 더욱 안정적으로 동작합니다. 즉 uBOL 자체는 콘텐츠 차단을 하는 동안 CPU/메모리 리소스를 소비하지 않습니다. uBOL 서비스워커 프로세스는 사용자가 팝업 창이나 설정을 열었을 _때에만_ 동작합니다. - -uBOL은 설치 시 광범위한 "읽기 및 수정" 권한을 요구하지 않으므로, 설치 후 즉시 쓸 수 있는 기능들은 uBlock Origin이나 설치 시 광범위한 "읽기 및 수정" 권한을 요구하는 다른 콘텐츠 차단기에 비해 제한됩니다. - -하지만 uBOL에서는 원하는 특정 사이트에 대해 확장된 권한을 부여하여, 해당 사이트를 표면 필터링 및 스크립트 주입을 바탕으로 더욱 잘 필터링할 수 있습니다. - -주어진 사이트에 확장된 권한을 부여하려면, 팝업 창을 열고 필터링 모드를 '최적'이나 '완전'과 같이 더 높은 수준으로 선택하세요. - -브라우저는 확장 프로그램에 현재 사이트에 대한 추가 권한을 부여했을 때 발생할 수 있는 일에 대해 경고할 것이며, 권한 요청을 수락할지 거부할지 선택해야 합니다. - -현재 사이트에 대해 uBOL에 추가 권한을 부여하면, 해당 사이트의 콘텐츠를 더욱 잘 필터링할 수 있습니다. - -uBOL 설정 페이지에서 기본 필터링 모드를 설정할 수 있습니다. 기본 모드를 '최적' 혹은 '완전'으로 설정하는 경우, uBOL에 모든 웹사이트에서 데이터를 읽고 수정할 수 있는 권한을 부여해야 합니다. - -본 확장 프로그램은 여전히 아래 목표를 달성하기 위해 개발 중인 단계입니다. - -- 설치 시 광범위한 호스트 권한을 요구하지 않고, 사용자가 사이트마다 명시적으로 확장된 권한을 부여할 수 있도록 합니다. - -- 완전히 선언적으로 구현하여 CPU/메모리 효율성과 신뢰성을 확보합니다. diff --git a/platform/mv3/description/webstore.lt.txt b/platform/mv3/description/webstore.lt.txt index e03fa801ee7f0..ef089202b9565 100644 --- a/platform/mv3/description/webstore.lt.txt +++ b/platform/mv3/description/webstore.lt.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -7,24 +7,6 @@ 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 does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff --git a/platform/mv3/description/webstore.lv.txt b/platform/mv3/description/webstore.lv.txt index 078cf7f4f9b48..129af3d1bbb85 100644 --- a/platform/mv3/description/webstore.lv.txt +++ b/platform/mv3/description/webstore.lv.txt @@ -1,30 +1,12 @@ -uBO Lite (uBOL) ir *bezatļauju* uz MV3 balstīts satura aizturētājs. +uBO Lite (uBOL) — uz MV3 balstīts satura aizturētājs. -Noklusējuma nosacījumu kopa atbilst uBokc Origin noklusējuma aizturēšanas kopai: +Noklusējuma nosacījumu kopa atbilst uBock Origin noklusējuma aizturēšanas kopai: - uBlock Origin iebūvētie aizturēšanas saraksti - EasyList - EasyPrivacy -- Pētera Lova (Peter Lowe) reklāmu un izsakošanas serveru saraksts +- Pētera Lova (Peter Lowe) reklāmu un izsekošanas serveru saraksts -Vairāk nosacījumu kopu var 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. - -uBOL nav nepieciešamas plašas "lasīt un pārveidot datus" atļaujas uzstādīšanas laikā, tāpēc tam ir ierobežotas spējas pēc noklusējuma, salīdzinājumā ar uBlock Origin vai citiem satura aizturētājiem, kas pieprasa plašas "lasīt un pārveidot datus" atļaujas uzstādīšanas laikā. - -Tomēr uBOL ļauj piešķirt paplašinātās atļaujas *tieši* noteiktās vietnēs pēc izvēles, lai tas varētu labāk veikt aizturēšanu tajās, izmantojot kosmētisku aizturēšanu un skriptu ievietošanu. - -Lai nodrošinātu paplašinātas piekļuves tiesības noteiktā vietnē, jāatver uznirstošais logs un jāizvēlas striktāks aizturēšanas veids, kā, piemēram, "Labākais" vai "Pilnīgais". - -Pārlūks tad brīdinās ietekmi, ko radīs paplašinājuma pieprasīto papildu atļauju nodrošināšana pašreizējā vietnē, un būs jānorāda, vai pieprasījums tiek apstiprināts vai noraidīts. - -Ja pašreizējā vietnē tiek apstiprināts uBOL papildu atļauju pieprasījums, paplašinājums varēs labāk veikt satura aizturēšanu. - -Noklusējuma aizturēšanas veids ir norādāms uBOL uzstādījumu lapā. Ja tiek izvēlēts "Labākais" vai "Pilnīgais" kā noklusējuma, tad būs nepieciešams nodrošināt uBOL tiesības rakstīt un pārveidot datus visās tīmekļa vietnēs. - -Jāpatur prātā, ka šī iespēja joprojām tiek izstrādāta ar šādiem mērķiem: - -- Nav plašu saimniekdatora atļauju uzstādīšanas laikā -- paplašinātas atļaujas nodrošina lietotājs atsevišķi katrai vietnei. - -- Pilnībā vispārīgs - uzticamībai un procesora/atmiņas lietderīgai izmantošanai. diff --git a/platform/mv3/description/webstore.mk.txt b/platform/mv3/description/webstore.mk.txt index e03fa801ee7f0..de9010a73fc69 100644 --- a/platform/mv3/description/webstore.mk.txt +++ b/platform/mv3/description/webstore.mk.txt @@ -1,30 +1,12 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. -The default ruleset corresponds to uBlock Origin's default filterset: +Стандардниот сет на правила одговара на стандардниот филтер сет на 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 does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. +uBOL е целосно декларативен, што значи дека не е потребен траен процес на uBOL за филтрирање да се одвива, а филтрирањето на содржини врз основа на инјекција на CSS/JS се извршува со сигурност од самото браузер, а не од самата екстензија. Ова значи дека самиот uBOL не консумира ресурси на CPU/меморија додека блокирањето на содржини е во тек - процесот на службениот работник на uBOL е потребен _само_ кога ќе е потребен со попап панел или страниците со опции. diff --git a/platform/mv3/description/webstore.ml.txt b/platform/mv3/description/webstore.ml.txt index 9237bc276067f..f151132e6a5cc 100644 --- a/platform/mv3/description/webstore.ml.txt +++ b/platform/mv3/description/webstore.ml.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) ഒരു *അനുമതി-കുറവ്* MV3 അടിസ്ഥാനമാക്കിയുള്ള ഉള്ളടക്ക ബ്ലോക്കറാണ്. +uBO Lite (uBOL) is an MV3-based content blocker. ഡിഫോൾട്ട് റൂൾസെറ്റ് uBlock Origin-ന്റെ ഡിഫോൾട്ട് ഫിൽട്ടർസെറ്റുമായി യോജിക്കുന്നു: @@ -7,24 +7,6 @@ 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-ന്റെ സേവന വർക്കർ പ്രോസസ്സ് ആവശ്യമാണ്. - -ഇൻസ്റ്റാളേഷൻ സമയത്ത് uBOL ന് വിശാലമായ "ഡാറ്റ വായിക്കാനും പരിഷ്‌ക്കരിക്കാനും" അനുമതി ആവശ്യമില്ല, അതിനാൽ uBlock ഒറിജിൻ അല്ലെങ്കിൽ മറ്റ് ഉള്ളടക്ക ബ്ലോക്കറുകൾ എന്നിവയുമായി താരതമ്യപ്പെടുത്തുമ്പോൾ അതിന്റെ പരിമിതമായ കഴിവുകൾ ഇൻസ്റ്റാളേഷൻ സമയത്ത് വിശാലമായ "ഡാറ്റ വായിക്കാനും പരിഷ്‌ക്കരിക്കാനും" അനുമതികൾ ആവശ്യമാണ്. - -എന്നിരുന്നാലും, നിങ്ങൾ തിരഞ്ഞെടുക്കുന്ന നിർദ്ദിഷ്ട സൈറ്റുകളിൽ വിപുലീകൃത അനുമതികൾ *വ്യക്തമായി* നൽകാൻ uBOL നിങ്ങളെ അനുവദിക്കുന്നു, അതുവഴി കോസ്മെറ്റിക് ഫിൽട്ടറിംഗും സ്ക്രിപ്റ്റ്ലെറ്റ് കുത്തിവയ്പ്പുകളും ഉപയോഗിച്ച് ആ സൈറ്റുകളിൽ മികച്ച രീതിയിൽ ഫിൽട്ടർ ചെയ്യാൻ കഴിയും. - -തന്നിരിക്കുന്ന സൈറ്റിൽ വിപുലമായ അനുമതികൾ നൽകുന്നതിന്, പോപ്പ്അപ്പ് പാനൽ തുറന്ന് ഒപ്റ്റിമൽ അല്ലെങ്കിൽ കംപ്ലീറ്റ് പോലുള്ള ഉയർന്ന ഫിൽട്ടറിംഗ് മോഡ് തിരഞ്ഞെടുക്കുക. - -നിലവിലെ സൈറ്റിൽ വിപുലീകരണം അഭ്യർത്ഥിച്ച അധിക അനുമതികൾ നൽകുന്നതിന്റെ ഫലങ്ങളെക്കുറിച്ച് ബ്രൗസർ നിങ്ങൾക്ക് മുന്നറിയിപ്പ് നൽകും, നിങ്ങൾ അഭ്യർത്ഥന സ്വീകരിക്കുകയോ നിരസിക്കുകയോ ചെയ്യണോ എന്ന് നിങ്ങൾ ബ്രൗസറിനോട് പറയേണ്ടിവരും. - -നിലവിലെ സൈറ്റിൽ കൂടുതൽ അനുമതികൾക്കായുള്ള uBOL-ന്റെ അഭ്യർത്ഥന നിങ്ങൾ അംഗീകരിക്കുകയാണെങ്കിൽ, നിലവിലെ സൈറ്റിനായി മികച്ച ഉള്ളടക്കം ഫിൽട്ടർ ചെയ്യാൻ അതിന് കഴിയും. - -uBOL-ന്റെ ഓപ്‌ഷൻ പേജിൽ നിന്ന് നിങ്ങൾക്ക് ഡിഫോൾട്ട് ഫിൽട്ടറിംഗ് മോഡ് സജ്ജമാക്കാൻ കഴിയും. ഒപ്റ്റിമൽ അല്ലെങ്കിൽ കംപ്ലീറ്റ് മോഡ് ഡിഫോൾട്ടായി നിങ്ങൾ തിരഞ്ഞെടുക്കുകയാണെങ്കിൽ, എല്ലാ വെബ്‌സൈറ്റുകളിലെയും ഡാറ്റ വായിക്കാനും പരിഷ്‌ക്കരിക്കാനും നിങ്ങൾ uBOL-ന് അനുമതി നൽകേണ്ടതുണ്ട്. - -ഈ അന്തിമ ലക്ഷ്യങ്ങളോടെ ഇത് ഇപ്പോഴും പുരോഗമിക്കുന്ന ഒരു ജോലിയാണെന്ന് ഓർമ്മിക്കുക: - -- ഇൻസ്റ്റാളേഷൻ സമയത്ത് ബ്രോഡ് ഹോസ്റ്റ് അനുമതികളൊന്നുമില്ല -- ഓരോ സൈറ്റിന്റെ അടിസ്ഥാനത്തിൽ വിപുലീകൃത അനുമതികൾ ഉപയോക്താവ് വ്യക്തമായി നൽകുന്നു. - -- വിശ്വാസ്യതയ്ക്കും സിപിയു/മെമ്മറി കാര്യക്ഷമതയ്ക്കും പൂർണ്ണമായും പ്രഖ്യാപനം. diff --git a/platform/mv3/description/webstore.mr.txt b/platform/mv3/description/webstore.mr.txt index e03fa801ee7f0..1747ea06e6335 100644 --- a/platform/mv3/description/webstore.mr.txt +++ b/platform/mv3/description/webstore.mr.txt @@ -1,30 +1,12 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) हे MV3-आधारित कंटेंट ब्लॉकर आहे. -The default ruleset corresponds to uBlock Origin's default filterset: +डीफॉल्ट नियमसंच uBlock Origin च्या डीफॉल्ट फिल्टरसेटशी संबंधित आहे: -- uBlock Origin's built-in filter lists +- uBlock Origin च्या बिल्ट-इन फिल्टर लिस्ट - EasyList - EasyPrivacy -- Peter Lowe’s Ad and tracking server list +- पीटर लोवची जाहिरात आणि ट्रॅकिंग सर्व्हर यादी -You can add more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. +तुम्ही पर्याय पृष्ठाला भेट देऊन अधिक नियम संच सक्षम करू शकता -- पॉपअप पॅनेलमधील _Cogs_ चिन्हावर क्लिक करा. -uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. +uBOL पूर्णपणे घोषणात्मक आहे, म्हणजे फिल्टरिंगसाठी कायमस्वरूपी uBOL प्रक्रियेची गरज नाही, आणि CSS/JS इंजेक्शनवर आधारित सामग्री फिल्टरिंग ब्राउझरच्याच मदतीने विश्वासार्हपणे होते, विस्ताराद्वारे नव्हे. याचा अर्थ असा की सामग्री ब्लॉकिंग चालू असताना uBOL स्वतः CPU/मेमरी संसाधने वापरत नाही — uBOL चा सर्व्हिस वर्कर प्रोसेस फक्त तेव्हाच लागतो जेव्हा तुम्ही पॉपअप पॅनल किंवा पर्याय पृष्ठांशी संवाद साधता. diff --git a/platform/mv3/description/webstore.ms.txt b/platform/mv3/description/webstore.ms.txt index 2a48cf613a824..54db9cc43237b 100644 --- a/platform/mv3/description/webstore.ms.txt +++ b/platform/mv3/description/webstore.ms.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) ialah penyekat kandungan berasaskan MV3. +uBO Lite (uBOL) is an MV3-based content blocker. Set peraturan lalai sepadan dengan set penapis lalai uBlock Origin: @@ -7,24 +7,6 @@ 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. - -uBOL tidak memerlukan kebenaran "baca dan ubah suai data" yang luas pada masa pemasangan, oleh itu keupayaan terhadnya di luar kotak berbanding dengan uBlock Origin atau penyekat kandungan lain yang memerlukan kebenaran "baca dan ubah suai data" yang luas pada masa pemasangan. - -Walau bagaimanapun, uBOL membenarkan anda *dengan jelas* memberikan kebenaran lanjutan pada tapak tertentu pilihan anda supaya ia boleh menapis dengan lebih baik pada tapak tersebut menggunakan penapisan kosmetik dan suntikan skrip. - -Untuk memberikan kebenaran lanjutan pada tapak tertentu, buka panel timbul dan pilih mod penapisan yang lebih tinggi seperti Optimum atau Lengkap. - -Penyemak imbas kemudian akan memberi amaran kepada anda tentang kesan pemberian kebenaran tambahan yang diminta oleh sambungan pada tapak semasa dan anda perlu memberitahu penyemak imbas sama ada anda menerima atau menolak permintaan tersebut. - -Jika anda menerima permintaan uBOL untuk mendapatkan kebenaran tambahan pada tapak semasa, ia akan dapat menapis kandungan dengan lebih baik untuk tapak semasa. - -Anda boleh menetapkan mod penapisan lalai dari halaman pilihan 'uBOL'. Jika anda memilih mod Optimum atau Lengkap sebagai mod lalai, anda perlu memberikan uBOL kebenaran untuk membaca dan mengubah suai data pada semua tapak web. - -Perlu diingat bahawa ini masih dalam proses, dengan matlamat akhir ini: - -- Tiada kebenaran hos pada masa pemasangan -- kebenaran lanjutan diberikan secara eksplisit oleh pengguna pada asas setiap tapak. - -- Deklaratif sepenuhnya untuk kebolehpercayaan dan kecekapan CPU/memori. diff --git a/platform/mv3/description/webstore.nb.txt b/platform/mv3/description/webstore.nb.txt index c45f9a527c080..eab6ff5fe700e 100644 --- a/platform/mv3/description/webstore.nb.txt +++ b/platform/mv3/description/webstore.nb.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) er en *tillatelses-begrenset* MV3-basert innholdsblokkerer. +uBO Lite (uBOL) er en MV3-basert innholdsblokkerer. Standardregelsettet tilsvarer standardfiltersettet til uBlock Origin: @@ -10,21 +10,3 @@ Standardregelsettet tilsvarer standardfiltersettet til uBlock Origin: Du kan legge til flere regelsett ved å gå til innstillingssiden -- klikk _Tannhjul_-ikonet i oppsprettspanelet. uBOL er fullstendig deklarativ, noe som betyr at det ikke er behov for en permanent uBOL-prosess for at filtreringen skal skje, og CSS/JS-injeksjonsbasert innholdsfiltrering utføres pålitelig av nettleseren selv i stedet for av utvidelsen. Dette betyr at uBOL selv ikke bruker CPU/minneressurser mens innholdsblokkering pågår -- uBOL's service worker-prosess kreves _bare_ når du samhandler med oppsprettspanelet eller innstillingssidene. - -uBOL krever ikke bred "lese og endre data"-tillatelse under installasjonen, derav begrensede muligheter i utgangspunktet sammenlignet med uBlock Origin eller andre innholdsblokkerere som krever bred "lese og endre data"-tillatelse under installasjonen. - -Men, uBOL lar deg *uttrykkelig* gi utvidede tillatelser på bestemte nettsteder du velger, slik at uBOL bedre kan filtrere på disse nettstedene ved bruk av kosmetisk filtrering og skriptlet-injeksjoner. - -For å gi utvidede tillatelser på et gitt nettsted, åpne oppsprettspanelet og velg en høyere filtreringsmodus som Optimal eller Fullstendig. - -Nettleseren vil da advare deg om effektene av å gi de ekstra tillatelsene som utvidelsen ber om på det gjeldende nettstedet, og du må fortelle nettleseren om du godtar eller avslår forespørselen. - -Hvis du godtar forespørselen fra uBOL om ekstra tillatelser på det gjeldende nettstedet, vil uBOL være i stand til å filtrere innhold bedre for det gjeldende nettstedet. - -Du kan angi standard filtreringsmodus fra innstillingssiden i uBOL. Hvis du velger Optimal eller Fullstendig modus som standard, må du gi uBOL tillatelsen til å lese og endre data på alle nettsteder. - -Husk at dette fortsatt er et arbeid som pågår, med disse sluttmålene: - -- Ingen brede vertstillatelser under installasjonen -- utvidede tillatelser gis uttrykkelig av brukeren på per-side-basis. - -- Helt deklarativt for pålitelighet og CPU/minneeffektivitet. diff --git a/platform/mv3/description/webstore.nl.txt b/platform/mv3/description/webstore.nl.txt index ecdf0c3465e51..fbf0c5c6a3284 100644 --- a/platform/mv3/description/webstore.nl.txt +++ b/platform/mv3/description/webstore.nl.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is een *toestemmingsloze* MV3-gebaseerde inhoudsblokkeerder. +uBO Lite (uBOL) is een op MV3 gebaseerde inhoudsblokkeerder. De standaard regelset komt overeen met de standaard filterset van uBlock Origin: @@ -7,24 +7,6 @@ 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. - -uBOL vereist geen brede toestemming voor het ‘lezen en aanpassen van gegevens’ tijdens installatie, vandaar de beperkte ingebouwde mogelijkheden ervan in vergelijking met uBlock Origin of andere inhoudsblokkeerders die brede toestemmingen voor het ‘lezen en aanpassen van gegevens’ vereisen tijdens installatie. - -U kunt in uBOL echter *expliciet* uitgebreide toestemmingen verlenen op bepaalde websites van uw keuze, zodat het op die websites beter kan filteren via cosmetische filtering en scriptlet-injecties. - -Om uitgebreide toestemmingen op een bepaalde website te verlenen, opent u het pop-uppaneel en kiest u een hogere filtermodus, zoals Optimaal of Volledig. - -De browser waarschuwt u dan over de gevolgen van het verlenen van de door de extensie aangevraagde aanvullende toestemmingen op de huidige website, en u dient de browser te laten weten of u de aanvraag accepteert of weigert. - -Als u de aanvraag van uBOL voor aanvullende toestemmingen op de huidige website accepteert, zal het inhoud voor de huidige website beter kunnen filteren. - -U kunt de standaard filtermodus instellen vanaf de optiespagina van uBOL. Als u de modus Optimaal of Volledig als de standaardmodus kiest, dient u uBOL de toestemming voor het lezen en aanpassen van gegevens op alle websites te verlenen. - -Onthoud dat dit nog werk in uitvoering is, met deze einddoelen: - -- Geen brede host-toestemmingen tijdens installatie -- uitgebreide toestemmingen worden expliciet en per website verleend door de gebruiker. - -- Volledig declaratief omwille van betrouwbaarheid en CPU-/geheugenefficiëntie. diff --git a/platform/mv3/description/webstore.oc.txt b/platform/mv3/description/webstore.oc.txt index e03fa801ee7f0..ef089202b9565 100644 --- a/platform/mv3/description/webstore.oc.txt +++ b/platform/mv3/description/webstore.oc.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -7,24 +7,6 @@ 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 does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff --git a/platform/mv3/description/webstore.pa.txt b/platform/mv3/description/webstore.pa.txt index b413fe39a4862..921403a394ffc 100644 --- a/platform/mv3/description/webstore.pa.txt +++ b/platform/mv3/description/webstore.pa.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) ਇੱਕ *ਬਿਨਾਂ ਇਜਾਜ਼ਤਾਂ* ਵਾਲਾ MV3-ਅਧਾਰਿਤ ਸਮੱਗਰੀ ਬਲਾਕਰ ਹੈ। +uBO Lite (uBOL) is an MV3-based content blocker. ਮੂਲ ਨਿਯਮ-ਸਮੂਹ uBlock Origin ਦੇ ਮੂਲ ਫਿਲਟਰ-ਸਮੂਹ ਨਾਲ ਸੰਬੰਧਿਤ ਹੈ: @@ -7,24 +7,6 @@ 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. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -ਯਾਦ ਰੱਖੋ ਕਿ ਇਹ ਕੰਮ ਹਾਲੇ ਵੀ ਜਾਰੀ ਹੈ, ਜਿਸ ਦੇ ਟੀਚੇ ਇਹ ਹਨ: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff --git a/platform/mv3/description/webstore.pl.txt b/platform/mv3/description/webstore.pl.txt index 4f5c5247c872f..45733625d03ff 100644 --- a/platform/mv3/description/webstore.pl.txt +++ b/platform/mv3/description/webstore.pl.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) to *niewymagający uprawnień* bloker treści oparty na MV3. +uBO Lite (uBOL) to bloker treści oparty na MV3. Domyślny zestaw reguł odpowiada domyślnemu zestawowi filtrów uBlock Origin: @@ -7,24 +7,6 @@ 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. - -uBOL w trakcie instalacji nie wymaga szerokich uprawnień do „odczytu i modyfikacji danych”, stąd jego ograniczone możliwości w porównaniu z uBlock Origin lub innymi blokerami treści, które w czasie instalacji wymagają szerokich uprawnień do „odczytu i modyfikacji danych”. - -Jednakże uBOL umożliwia *jawnie* udzielanie rozszerzonych uprawnień na określonych wybranych witrynach, dzięki czemu może lepiej filtrować te witryny za pomocą filtrowania kosmetycznego i wstrzykiwania skryptletów. - -Aby przyznać rozszerzone uprawnienia na danej witrynie, otwórz panel wyskakujący i wybierz wyższy tryb filtrowania, taki jak Optymalny lub Kompletny. - -Przeglądarka wyświetli ostrzeżenie o skutkach przyznania dodatkowych uprawnień wymaganych przez rozszerzenie na bieżącej witrynie i będziesz musiał poinformować przeglądarkę, czy akceptujesz, czy odrzucasz żądanie. - -Jeśli zaakceptujesz żądanie uBOL o dodatkowe uprawnienia na bieżącej witrynie, będzie on w stanie lepiej filtrować zawartość bieżącej witryny. - -Możesz ustawić domyślny tryb filtrowania na stronie opcji uBOL. Jeśli tryb Optymalny lub Pełny zostanie wybrany jako domyślny, trzeba będzie przyznać uBOL uprawnienia do odczytu i modyfikacji danych na wszystkich stronach internetowych. - -Należy pamiętać, że nadal trwają prace z następującymi celami końcowymi: - -– Brak szerokich uprawnień hosta w czasie instalacji – rozszerzone uprawnienia są przyznawane jawnie przez użytkownika na podstawie poszczególnych witryn. - -– Całkowicie deklaratywna niezawodność i wydajność procesora/pamięci. diff --git a/platform/mv3/description/webstore.pt_BR.txt b/platform/mv3/description/webstore.pt_BR.txt index 884ec649a4499..7e04ac9f88d86 100644 --- a/platform/mv3/description/webstore.pt_BR.txt +++ b/platform/mv3/description/webstore.pt_BR.txt @@ -1,4 +1,4 @@ -O uBO Lite (uBOL) é um bloqueador de conteúdo baseado no MV3 com menor permissão. +O uBO Lite (uBOL) é um bloqueador de conteúdo baseado no MV3. O conjunto de regras padrão corresponde ao conjunto de filtros padrão do uBlock Origin: @@ -7,24 +7,6 @@ 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 pop-up. O uBOL é totalmente declarativo, significando que não há necessidade de um processo permanente do uBOL para a filtragem ocorrer e a filtragem de conteúdo baseada em injeção do CSS/JS é realizada confiavelmente pelo próprio navegador ao invés da extensão. Isto significa que o próprio uBOL não consome recursos de CPU/memória enquanto o bloqueio de conteúdo está em andamento -- o processo do service worker do uBOL _só_ é necessário quando você interage com o painel do pop-up ou as páginas das opções. - -O uBOL não requer permissão ampla pra "ler e modificar dados" na hora da instalação, logo suas capacidades limitadas fora da caixa comparadas com o uBlock Origin ou outros bloqueadores de conteúdo requerem permissões amplas pra "ler e modificar dados" na hora da instalação. - -Contudo, o uBOL permite a você garantir *explicitamente* permissões estendidas em sites específicos de sua escolha pra que possa filtrar melhor esses sites usando filtragem cosmética e injeções de scriptlet. - -Pra conceder permissões estendidas num site dado, abra o painel do pop-up e escolha um modo de filtragem superior tal como Otimizado ou Completo. - -O navegador então avisará você sobre os efeitos de garantir as permissões adicionais requisitadas pela extensão no site atual e você terá que dizer ao navegador se você aceita ou recusa a requisição. - -Se você aceitar a requisição do uBOL por permissões adicionais no site atual ele será capaz de filtrar melhor o conteúdo do site atual. - -Você pode definir o modo de filtragem padrão na página de opções do uBOL. Se você escolher o Modo Otimizado ou Completo como o modo padrão você precisará garantir ao uBOL a permissão de ler e modificar os dados em todos os sites. - -Mantenha em mente que este ainda é um trabalho em progresso com estes objetivos finais: - -- Sem permissões amplas do hospedeiro na hora da instalação -- as permissões estendidas são garantidas explicitamente pelo usuário numa base por site. - -- Totalmente declarativo para confiabilidade e eficiência de CPU/memória. diff --git a/platform/mv3/description/webstore.pt_PT.txt b/platform/mv3/description/webstore.pt_PT.txt index fcd3823801406..9a317c90d2c68 100644 --- a/platform/mv3/description/webstore.pt_PT.txt +++ b/platform/mv3/description/webstore.pt_PT.txt @@ -1,30 +1,12 @@ -O uBO Lite (uBOL) é um bloqueador de conteúdo baseado no MV3 *sem permissões*. +O uBO Lite (uBOL) é um bloqueador de conteúdo baseado em MV3. -O conjunto de regras padrão corresponde ao conjunto de filtros padrão do uBlock Origin: +O conjunto de regras predefinido corresponde ao conjunto de filtros predefinido do uBlock Origin: - Listas de filtros integrados do uBlock Origin - EasyList - EasyPrivacy - Peter Lowe’s Ad and tracking server list -Pode 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_ no painel popup. -O uBOL é totalmente declarativo, o que elimina a necessidade de um processo ativo constante para a filtragem ocorrer. A injeção de CSS e JS para filtragem de conteúdo é efetuada de maneira confiável pelo navegador, não dependendo da extensão. Isso significa que o uBOL por si só não gasta recursos de CPU/memória enquanto o bloqueio de conteúdo está a acontecer -- o processo do trabalhador de serviço do uBOL é necessário apenas quando se interage com a janela flutuante ou as páginas de opções. - -uBOL não requer ampla permissão de "ler e modificar dados" no momento da instalação, daí as suas capacidades limitadas de pronto a usar em comparação com uBlock Origin ou outros bloqueadores de conteúdo que requerem amplas permissões de "ler e modificar dados" no momento da instalação. - -No entanto, o uBOL permite-lhe que *explicitamente* conceda permissões alargadas em websites específicos de sua escolha, para que possa filtrar melhor esses websites usando filtragem cosmética e injeções de scriptlet. - -Para conceder permissões alargadas num determinado sítio web, abra a janela flutuante e escolha um modo de filtragem superior, como 'Ideal' ou 'Completo'. - -O navegador irá avisá-lo sobre os efeitos da concessão das permissões adicionais solicitadas pela extensão no site atual, e terá que informar ao navegador se aceita ou recusa o pedido. - -Se aceitar o pedido do uBOL para permissões adicionais no site atual, o mesmo poderá filtrar melhor o conteúdo do site atual. - -Pode definir o modo de filtragem padrão na página de opções do uBOL. Se escolher o modo Ideal ou Completo como o modo predefinido, terá de conceder ao uBOL a permissão para ler e modificar dados em todos os sítios web. - -Tenha em mente que este ainda é um trabalho em curso, com estes objetivos finais: - -- Sem permissões amplas de anfitrião no momento da instalação -- permissões estendidas são concedidas explicitamente pelo utilizador numa base por site. - -- Totalmente declarativo para fiabilidade e eficiência de CPU/memória +O uBOL é totalmente declarativo, o que significa que não é necessário um processo permanente do uBOL para que a filtragem ocorra, e a filtragem de conteúdos baseada em injeção de CSS/JS é realizada de forma fiável pelo próprio navegador, e não pela extensão. Isto significa que o próprio uBOL não consome recursos de CPU/memória enquanto o bloqueio de conteúdo está ativo -- o processo do service worker do uBOL é necessário apenas quando interage com o painel popup ou com as páginas de opções. diff --git a/platform/mv3/description/webstore.ro.txt b/platform/mv3/description/webstore.ro.txt index 6e1f05d38f5f0..86ef894d53855 100644 --- a/platform/mv3/description/webstore.ro.txt +++ b/platform/mv3/description/webstore.ro.txt @@ -1,30 +1,12 @@ -uBO Lite (uBOL) este blocant de conținut experimental *fără permisiuni* bazat pe MV3. +uBO Lite (uBOL) este un blocker de conținut bazat pe MV3. Setul de reguli implicit corespunde setului de filtre implicit al uBlock Origin: Listele de filtre încorporate de uBlock Origin - EasyList - EasyPrivacy -- Oglas Peter Lowe i lista servera za praćenje +- -Lista de servere de anunț și de urmărire a lui Peter Lowe -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 +Puteți activa mai multe seturi de reguli accesând pagina de opțiuni - faceți clic pe pictograma _Cogs_ din panoul pop-up. uBOL este în întregime declarativ, ceea ce înseamnă că nu este nevoie de un proces uBOL permanent pentru ca filtrarea să aibă loc, iar filtrarea conținutului pe bază de injecție CSS/JS este realizată în mod sigur de browser în sine, mai degrabă decât de extensie. Aceasta înseamnă că uBOL în sine nu consumă resurse CPU/memorie în timp ce blocarea conținutului este în desfășurare -- procesul de lucru al serviciului uBOL este necesar _doar_ atunci când interacționați cu panoul pop-up sau cu paginile de opțiuni. - -uBOL nu necesită permisiunii extinse de „citire și modificare a datelor” în momentul instalării, astfel capacitățile sale limitate din momentul instalării în comparație cu uBlock Origin sau alte blocare de conținut necesită permisiuni largi de „citire și modificare a datelor” în momentul instalării. - -Cu toate acestea, uBOL vă permite să acordați *explicit* permisiuni extinse pe anumite site-uri alese de dvs., astfel încât să poată filtra mai bine pe acele site-uri folosind filtrarea cosmetică și injecțiile de scriptlet. - -Pentru a acorda permisiuni extinse pe un anumit site, deschideți panoul pop-up și alegeți un mod de filtrare mai ridicat, cum ar fi Optimal sau Complet. - -Browser-ul vă va avertiza apoi cu privire la efectele acordării permisiunilor suplimentare solicitate de extensie pe site-ul curent și va trebui să-i precizați browserului dacă acceptați sau refuzați cererea. - -Dacă acceptați solicitarea uBOL pentru permisiuni suplimentare pe site-ul curent, acesta va putea filtra mai bine conținutul pentru site-ul curent. - -Puteți seta modul implicit de filtrare din pagina de opțiuni a uBOL. Dacă alegeți modul optim sau complet ca implicit, va trebui să acordați lui uBOL permisiunea de a citi și modifica datele de pe toate site-urile web. - -Rețineți că aceasta este în curs de desfășurare, cu aceste obiective finale: - -- Fără permisiuni de gazdă largi în momentul instalării - permisiunile extinse sunt acordate în mod explicit de către utilizator pe bază de site. - -- Complet declarativ pentru fiabilitate și eficiență CPU/memorie. diff --git a/platform/mv3/description/webstore.ru.txt b/platform/mv3/description/webstore.ru.txt index 637d7cb444841..e38d774f3a5e2 100644 --- a/platform/mv3/description/webstore.ru.txt +++ b/platform/mv3/description/webstore.ru.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) — это блокировщик содержимого, *не требующий разрешений*, и основанный на MV3. +uBO Lite (uBOL) — это блокировщик веб-элементов на базе MV3. Стандартный набор правил соответствует типовому набору фильтров uBlock Origin: @@ -7,24 +7,6 @@ uBO Lite (uBOL) — это блокировщик содержимого, *не - EasyPrivacy - Список рекламных и отслеживающих серверов от Peter Lowe -Вы можете добавить больше правил, посетив страницу настроек -- нажмите на значок_Шестеренок на всплывающей панели. +Вы можете активировать больше списков правил на странице настроек -- нажмите на значок _Шестерёнки_ на всплывающей панели. uBOL - полностью декларативный, т.е. для фильтрации не нужен постоянно выполняющийся uBOL процесс, а фильтрация контента, основанная на внедрении CSS/JS, производится непосредственно браузером. Это значит, что дополнение uBOL не расходует ресурсы ЦПУ/памяти, когда происходит блокировка рекламы -- служебный процесс uBOL запускается, _только_ когда вы вносите изменения на всплывающей панели или странице настроек. - -uBOL не требует разрешение на полное "чтение и изменение данных" в момент установки, поэтому имеет ограниченные возможности по сравнению с uBlock Origin, и другими блокировщиками контента, которые требуют полное разрешение на "чтение и изменение данных" в момент установки. - -Однако uBOL позволяет *намеренно* давать расширенные разрешения для определенных сайтов - по вашему усмотрению, чтобы эффективнее работать, используя косметическую фильтрацию и scriptlet-внедрения. - -Для предоставления расширенных разрешений на текущем сайте - откройте всплывающую панель и выберите повышенный режим фильтрации: Оптимальный или Полный. - -Далее браузер выдаст предупреждение об эффектах предоставления расширенных разрешений, запрошенных дополнением на текущем сайте, и надо будет выбрать: принять или отклонить этот запрос. - -Если вы принимаете запрос uBOL на предоставление дополнительных разрешений, тогда дополнение сможет эффективнее фильтровать контент на текущем сайте. - -Вы можете установить стандартный режим фильтрации на странице настроек uBOL. Если вы выбираете Оптимальный или Полный режим - режимом по умолчанию, необходимо предоставить uBOL разрешение на чтение и изменение данных на всех веб-сайтах. - -Помните, что данный проект - в активной фазе разработки, преследующей следующие цели: - -- Работа с ограниченными разрешениями при установке -- расширенные разрешения пользователь выдает по своему усмотрению, каждому сайту отдельно. - -- Полностью декларативная работа - для надежности и эффективного использования ЦПУ/памяти. diff --git a/platform/mv3/description/webstore.si.txt b/platform/mv3/description/webstore.si.txt index e03fa801ee7f0..939dc39c17357 100644 --- a/platform/mv3/description/webstore.si.txt +++ b/platform/mv3/description/webstore.si.txt @@ -1,30 +1,12 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) යනු MV3-පාදක අන්තර්ගත අවහිර කරන්නා වේ. -The default ruleset corresponds to uBlock Origin's default filterset: +පෙරනිමි රීති කට්ටලය uBlock Origin හි පෙරනිමි පෙරහන් කට්ටලයට අනුරූප වේ: -- uBlock Origin's built-in filter lists -- EasyList -- EasyPrivacy -- Peter Lowe’s Ad and tracking server list +- uBlock Origin හි බිල්ට් පෙරහන් ලැයිස්තු +- පහසු ලැයිස්තුව +- පහසු පෞද්ගලිකත්වය +- පීටර් ලෝගේ දැන්වීම් සහ ලුහුබැඳීමේ සේවාදායක ලැයිස්තුව -You can add more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. +විකල්ප පිටුවට පිවිසීමෙන් ඔබට තවත් නීති කට්ටල සක්‍රීය කළ හැකිය -- උත්පතන පැනලයේ _Cogs_ නිරූපකය ක්ලික් කරන්න. -uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. +uBOL සම්පූර්ණයෙන්ම ප්‍රකාශනාත්මකයි, එනම් පෙරීම සිදුවීමට ස්ථිර uBOL ක්‍රියාවලියක් අවශ්‍ය නොවන අතර, CSS/JS එන්නත්-පාදක අන්තර්ගත පෙරීම දිගුව මගින් නොව බ්‍රවුසරය විසින්ම විශ්වාසදායක ලෙස සිදු කරයි. මෙයින් අදහස් කරන්නේ අන්තර්ගත අවහිර කිරීම සිදුවෙමින් පවතින අතරතුර uBOL විසින්ම CPU/මතක සම්පත් පරිභෝජනය නොකරන බවයි -- ඔබ උත්පතන පැනලය හෝ විකල්ප පිටු සමඟ අන්තර් ක්‍රියා කරන විට uBOL හි සේවා සේවක ක්‍රියාවලිය _only_ අවශ්‍ය වේ. diff --git a/platform/mv3/description/webstore.sk.txt b/platform/mv3/description/webstore.sk.txt index 686e41f918185..2869ff68f5a29 100644 --- a/platform/mv3/description/webstore.sk.txt +++ b/platform/mv3/description/webstore.sk.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) je blokovač obsahu založený na MV3 *bez povolenia*. +uBO Lite (uBOL) je blokovač obsahu založený na MV3. Predvolený súbor pravidiel zodpovedá predvolenému súboru filtrov uBlock Origin: @@ -7,24 +7,6 @@ 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í. - -uBOL pri inštalácii nevyžaduje všeobecné oprávnenie "čítať a upravovať údaje", preto má obmedzené možnosti v porovnaní s uBlock Origin alebo inými blokovačmi obsahu, ktoré pri inštalácii vyžadujú všeobecné oprávnenie "čítať a upravovať údaje". - -uBOL vám však umožňuje *výslovne* udeliť všebecné oprávnenia na konkrétne stránky podľa vášho výberu, aby mohol lepšie filtrovať na týchto stránkach pomocou kozmetického filtrovania a injektovaných skriptletov. - -Ak chcete udeliť všeobecné oprávnenia na danom webe, otvorte vyskakovací panel a vyberte vyšší režim filtrovania, napríklad Optimálny alebo Kompletný. - -Prehliadač vás potom upozorní na dôsledky udelenia dodatočných oprávnení požadovaných rozšírením na aktuálnej stránke a vy budete musieť prehliadaču oznámiť, či požiadavku prijímate alebo odmietate. - -Ak prijmete žiadosť uBOL o dodatočné povolenia na aktuálnom webe, bude môcť lepšie filtrovať obsah aktuálneho webu. - -Predvolený režim filtrovania môžete nastaviť na stránke možností uBOL. Ak ako predvolený režim vyberiete Optimálny alebo Kompletný režim, budete musieť uBOL-u udeliť oprávnenie na čítanie a úpravu údajov na všetkých webových stránkach. - -Majte na pamäti, že na tomto projekte sa stále pracuje, pričom jeho konečné ciele sú takéto: - -- Žiadne všeobecné oprávnenia hostiteľa v čase inštalácie -- rozšírené oprávnenia udeľuje používateľ explicitne pre jednotlivé stránky. - -- Úplne deklaratívne pre spoľahlivosť a efektivitu CPU/pamäte. diff --git a/platform/mv3/description/webstore.sl.txt b/platform/mv3/description/webstore.sl.txt index e03fa801ee7f0..ef089202b9565 100644 --- a/platform/mv3/description/webstore.sl.txt +++ b/platform/mv3/description/webstore.sl.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -7,24 +7,6 @@ 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 does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff --git a/platform/mv3/description/webstore.so.txt b/platform/mv3/description/webstore.so.txt index e03fa801ee7f0..ef089202b9565 100644 --- a/platform/mv3/description/webstore.so.txt +++ b/platform/mv3/description/webstore.so.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -7,24 +7,6 @@ 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 does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff --git a/platform/mv3/description/webstore.sq.txt b/platform/mv3/description/webstore.sq.txt index 6b087c3c404ac..45ed3c8e9ff38 100644 --- a/platform/mv3/description/webstore.sq.txt +++ b/platform/mv3/description/webstore.sq.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) është një bllokues *i pavarur* që funksionon sipas modelit MV3. +uBO Lite (uBOL) është një bllokues materialesh sipas modelit MV3. Rregullat e tij janë të barasvlershme me filtrat standardë që përdor uBlock Origin: @@ -7,24 +7,6 @@ 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. - -uBO Lite nuk kërkon leje shtesë për "leximin dhe modifikimin e të dhënave" kur e instaloni, prandaj fillimisht ka aftësi më të kufizuara sesa uBlock Origin apo bllokuesit e tjerë që kërkojnë leje shtesë për "leximin dhe modifikimin e të dhënave" gjatë instalimit. - -Megjithatë ju mund t'i jepni uBOL leje të posaçme *eksplicite* për ato uebsajte që doni, në mënyrë që t'i filtrojë më mirë me filtra kozmetikë dhe skripte. - -Lejet e posaçme për uebsajtet jepen nëpërmjet panelit modal duke zgjedhur mënyrën e filtrimit Optimal ose Komplet. - -Më tej shfletuesi do ju informojë për efektet e dhënies së këtyre lejeve për uebsajtin në fjalë dhe ju duhet ta pranoni ose refuzoni kërkesën. - -Po ta pranoni dhënien e lejeve shtesë për uebsajtin në fjalë, uBOL do mundet ta filtrojë më mirë atë. - -Në faqen e opsioneve të uBOL mund të përcaktoni mënyrën standarde të filtrimit. Nëse vendosni si standard mënyrën Optimale ose Komplete, uBOL do ju marrë leje për leximin dhe modifikimin e të dhënave në të gjitha uebsajtet. - -Kini parasysh se ky projekt është në zhvillim e sipër sipas këtyre objektivave: - -- Instalohet pa leje shtesë – lejet e posaçme për çdo uebsajt jepen në mënyrë eksplicite nga përdoruesi. - -- Tërësisht deklarativ për të qenë më i qëndrueshëm dhe eficient me procesorin/memorien. diff --git a/platform/mv3/description/webstore.sr.txt b/platform/mv3/description/webstore.sr.txt index 065d6c0249db2..92b0eb100a8d8 100644 --- a/platform/mv3/description/webstore.sr.txt +++ b/platform/mv3/description/webstore.sr.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) је блокатор садржаја *без дозвола*, заснован на MV3. +uBO Lite (uBOL) је блокатор садржаја заснован на MV3. Подразумевани скуп правила одговара подразумеваном скупу филтера uBlock Origin-а: @@ -7,24 +7,6 @@ uBO Lite (uBOL) је блокатор садржаја *без дозвола*, - EasyPrivacy - Peter Lowe’s Ad and tracking server list -Можете додати још скупова правила тако што ћете посетити страницу са опцијама - кликните на иконицу зупчаника у искачућем панелу. +Можете омогућити још скупова правила тако што ћете посетити страницу са опцијама -- кликните на иконицу зупчаника у искачућем панелу. uBOL је потпуно декларативан, што значи да нема потребе за трајним uBOL процесом да би дошло до филтрирања, а филтрирање садржаја засновано на убацивању CSS/JS се обавља поуздано од стране самог прегледача, а не проширења. То значи да сам uBOL не троши CPU/меморијске ресурсе док је блокирање садржаја у току -- сервисни радни процес uBOL-а је потребан _само_ када ступите у интеракцију са искачућим панелом или страницама опција. - -uBOL не захтева широку дозволу за „читање и измену података” у тренутку инсталације, стога су његове ограничене могућности ван оквира у поређењу са uBlock Origin-ом или другим блокаторима садржаја који захтевају широке дозволе за „читање и измену података” у тренутку инсталације. - -Међутим, uBOL вам омогућује да *експлицитно* доделите проширене дозволе на одређеним сајтовима по вашем избору тако да може боље да филтрира те сајтове користећи козметичко филтрирање и ињекције скриптлета. - -Да бисте доделили проширене дозволе за дати сајт, отворите искачући панел и изаберите виши режим филтрирања, као што је Оптимално или Комплетно. - -Прегледач ће вас тада упозорити на ефекте давања додатних дозвола које захтева проширење на тренутном сајту, а ви ћете морати да кажете прегледачу да ли прихватате или одбијате захтев. - -Ако прихватите uBOL-ов захтев за додатне дозволе на тренутном сајту, он ће моћи боље да филтрира садржај за тренутни сајт. - -Можете подесити подразумевани режим филтрирања на uBOL-овој страници са опцијама. Ако изаберете режим Оптимално или Комплетно као подразумевани, мораћете да доделите uBOL-у дозволу да чита и мења податке на свим веб сајтовима. - -Имајте на уму да је ово још увек рад у току, са овим крајњим циљевима: - -– Нема широких дозвола за хост у тренутку инсталације – проширене дозволе се експлицитно додељују од стране корисника на основу сваког сајта. - -- Потпуно декларативан за поузданост и ефикасност CPU/меморије. diff --git a/platform/mv3/description/webstore.sv.txt b/platform/mv3/description/webstore.sv.txt index 0355bd0ae45b3..47216fb547a4f 100644 --- a/platform/mv3/description/webstore.sv.txt +++ b/platform/mv3/description/webstore.sv.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) är en *behörighetslös* MV3-baserad innehållsblockerare. +uBO Lite (uBOL) är en MV3-baserad innehållsblockerare. Standardregeluppsättningen motsvarar uBlock Origins standardfilteruppsättning: @@ -7,24 +7,6 @@ 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. - -uBOL kräver inte högre behörighet för "läs och ändra data" vid installationen, därav dess begränsade möjligheter jämfört med uBlock Origin eller andra innehållsblockerare som kräver högre behörighet för "läs och ändra data" vid installationen. - -Däremot låter uBOL dig *uttryckligen* ge utökade behörigheter på specifika webbplatser du väljer så att den bättre kan filtrera på dessa webbplatser med hjälp av kosmetisk filtrering och scriptletinjektioner. - -För att ge utökade behörigheter på en viss webbplats, öppna popup-panelen och välj ett högre filtreringsläge som optimal eller fullständig. - -Webbläsaren kommer sedan att varna dig om effekterna av att bevilja de ytterligare behörigheter som tillägget begär på den aktuella webbplatsen och du måste tala om för webbläsaren om du accepterar eller avslår begäran. - -Om du accepterar uBOLs begäran om ytterligare behörigheter på den aktuella webbplatsen kommer den att kunna filtrera innehåll för den aktuella webbplatsen bättre. - -Du kan ställa in standardfiltreringsläget från uBOLs alternativsida. Om du väljer läge optimalt eller fullständigt som standard måste du ge uBOL behörighet att läsa och ändra data på alla webbplatser. - -Tänk på att detta fortfarande är ett pågående arbete med dessa slutmål: - -- Inga högre värdbehörigheter vid installationen - utökade behörigheter ges uttryckligen av användaren per webbplats. - -- Helt deklarativt för tillförlitlighet och CPU/minneseffektivitet. diff --git a/platform/mv3/description/webstore.sw.txt b/platform/mv3/description/webstore.sw.txt index e03fa801ee7f0..ef089202b9565 100644 --- a/platform/mv3/description/webstore.sw.txt +++ b/platform/mv3/description/webstore.sw.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -7,24 +7,6 @@ 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 does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff --git a/platform/mv3/description/webstore.ta.txt b/platform/mv3/description/webstore.ta.txt index e03fa801ee7f0..ef089202b9565 100644 --- a/platform/mv3/description/webstore.ta.txt +++ b/platform/mv3/description/webstore.ta.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -7,24 +7,6 @@ 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 does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff --git a/platform/mv3/description/webstore.te.txt b/platform/mv3/description/webstore.te.txt index 2f0c87d02703a..ef089202b9565 100644 --- a/platform/mv3/description/webstore.te.txt +++ b/platform/mv3/description/webstore.te.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) అనేది *అనుమతి-తక్కువ* MV3-ఆధారిత కంటెంట్ బ్లాకర్. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -7,24 +7,6 @@ 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కి ఇన్‌స్టాల్ సమయంలో విస్తృత "డేటాను చదవడం మరియు సవరించడం" అనుమతి అవసరం లేదు, అందువల్ల uBlock ఆరిజిన్ లేదా ఇన్‌స్టాల్ సమయంలో విస్తృతమైన "డేటాను చదవడం మరియు సవరించడం" అనుమతులు అవసరమయ్యే ఇతర కంటెంట్ బ్లాకర్‌లతో పోలిస్తే దాని పరిమిత సామర్థ్యాలు బాక్స్ వెలుపల ఉన్నాయి. - -అయితే, uBOL మీకు నచ్చిన నిర్దిష్ట సైట్‌లలో పొడిగించిన అనుమతులను *స్పష్టంగా* మంజూరు చేయడానికి మిమ్మల్ని అనుమతిస్తుంది, తద్వారా కాస్మెటిక్ ఫిల్టరింగ్ మరియు స్క్రిప్ట్‌లెట్ ఇంజెక్షన్‌లను ఉపయోగించి ఆ సైట్‌లలో మెరుగ్గా ఫిల్టర్ చేయవచ్చు. - -ఇచ్చిన సైట్‌లో పొడిగించిన అనుమతులను మంజూరు చేయడానికి, పాప్‌అప్ ప్యానెల్‌ను తెరిచి, ఆప్టిమల్ లేదా కంప్లీట్ వంటి అధిక ఫిల్టరింగ్ మోడ్‌ను ఎంచుకోండి. - -ప్రస్తుత సైట్‌లో పొడిగింపు ద్వారా అభ్యర్థించిన అదనపు అనుమతులను మంజూరు చేయడం వల్ల కలిగే ప్రభావాల గురించి బ్రౌజర్ మిమ్మల్ని హెచ్చరిస్తుంది మరియు మీరు అభ్యర్థనను అంగీకరించాలా లేదా తిరస్కరించాలా అని మీరు బ్రౌజర్‌కి తెలియజేయాలి. - -మీరు ప్రస్తుత సైట్‌లో అదనపు అనుమతుల కోసం uBOL అభ్యర్థనను అంగీకరిస్తే, అది ప్రస్తుత సైట్ కోసం కంటెంట్‌ను మెరుగ్గా ఫిల్టర్ చేయగలదు. - -మీరు uBOL ఎంపికల పేజీ నుండి డిఫాల్ట్ ఫిల్టరింగ్ మోడ్‌ను సెట్ చేయవచ్చు. మీరు డిఫాల్ట్‌గా ఆప్టిమల్ లేదా కంప్లీట్ మోడ్‌ని ఎంచుకుంటే, మీరు అన్ని వెబ్‌సైట్‌లలోని డేటాను చదవడానికి మరియు సవరించడానికి uBOLకి అనుమతిని మంజూరు చేయాలి. - -ఈ తుది లక్ష్యాలతో ఇది ఇంకా పురోగతిలో ఉందని గుర్తుంచుకోండి: - -- ఇన్‌స్టాల్ సమయంలో విస్తృత హోస్ట్ అనుమతులు లేవు -- పొడిగించిన అనుమతులు ప్రతి-సైట్ ప్రాతిపదికన వినియోగదారు ద్వారా స్పష్టంగా మంజూరు చేయబడతాయి. - -- విశ్వసనీయత మరియు CPU/మెమరీ సామర్థ్యం కోసం పూర్తిగా డిక్లరేటివ్. diff --git a/platform/mv3/description/webstore.th.txt b/platform/mv3/description/webstore.th.txt index e03fa801ee7f0..48241dbc4d697 100644 --- a/platform/mv3/description/webstore.th.txt +++ b/platform/mv3/description/webstore.th.txt @@ -1,30 +1,12 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. -The default ruleset corresponds to uBlock Origin's default filterset: +ชุดเงื่อนไขเริ่มต้นสอดคล้องกันกับค่าตัวกรองเริ่มต้นของ 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. +คุณสามารถเปิดใช้งานชุดเงื่อนไขเพิ่มเติมโดยไปที่เพจทางเลือก -- คลิก the _Cogs_ icon ที่แผงป๊อปอัพ -uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. +uBOL มีการประกาศอย่างชัดเจน ซึ่งหมายความว่าไม่ต้องมีกระบวนการ uBOL ถาวรในการคัดกรอง และการคัดกรองเนื้อหา CSS/JS injection-based จะดำเนินการได้อย่างน่าเชื่อถือด้วยตัวเบราว์เซอร์เองแทนที่จะเป็นส่วนขยาย สิ่งนี้หมายถึงตัว uBOL เองไม่ต้องผลาญทรัพยากรซีพียู/หน่วยความจำในขณะที่ทำการบล๊อก -- กระบวนการทำงานของ uBOL ใช้ required _only_ เมื่อคุณโต้ตอบกับแผงป๊อปอัพหรือเพจตัวเลือก diff --git a/platform/mv3/description/webstore.tr.txt b/platform/mv3/description/webstore.tr.txt index 125ca901419c5..14eef1229168e 100644 --- a/platform/mv3/description/webstore.tr.txt +++ b/platform/mv3/description/webstore.tr.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL), *izin gerektirmeyen* MV3 tabanlı bir içerik engelleyicidir. +uBO Lite (uBOL), MV3 tabanlı bir içerik engelleyicidir. Varsayılan kural seti, uBlock Origin'in varsayılan filtre setine karşılık gelir: @@ -7,24 +7,6 @@ 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 fazla kuralı aktif hale getirebilirsiniz, bunun için açılır paneldeki _dişli_ simgesine tıklayın. uBOL tamamen bildirimseldir, yani filtrelemenin gerçekleşmesi için kalıcı bir uBOL işlemine gerek yoktur, içerik filtreleme eklenti yerine tarayıcının kendisi tarafından CSS/JS yerleştirerek gerçekleştirilir. Bu, içerik engelleme devam ederken uBOL'nin kendisinin CPU/bellek kaynaklarını tüketmediği anlamına gelir -- uBOL'un hizmet çalışanı işlemi, _only_ açılan panel veya seçenek sayfalarıyla etkileşim kurduğunuzda gereklidir. - -uBOL, kurulum sırasında geniş "veri okuma ve değiştirme" izni gerektirmez, bu nedenle, kurulum sırasında geniş "veri okuma ve değiştirme" izinleri gerektiren uBlock Origin veya diğer içerik engelleyicilere kıyasla, kutudan çıkar çıkmaz sınırlı yetenekleri vardır. - -Bununla birlikte, uBOL, kozmetik filtreleme ve komut dosyası enjeksiyonları kullanarak bu sitelerde daha iyi filtre uygulayabilmesi için, seçtiğiniz belirli sitelerde *açıkça* genişletilmiş izinler vermenize izin verir. - -Belirli bir sitede genişletilmiş izinler vermek için açılır paneli açın ve Optimal veya Complete gibi daha yüksek bir filtreleme modu seçin. - -Ardından tarayıcı, uzantı tarafından istenen ek izinlerin geçerli sitede verilmesinin etkileri konusunda sizi uyaracak ve tarayıcıya isteği kabul edip etmediğinizi söylemeniz gerekecektir. - -uBOL'un mevcut site için ek izin talebini kabul ederseniz, mevcut site için içeriği daha iyi filtreleyebilecektir. - -Varsayılan filtreleme modunu uBOL'un seçenekler sayfasından ayarlayabilirsiniz. Varsayılan mod olarak Optimal veya Complete modunu seçerseniz, uBOL'a tüm web sitelerindeki verileri okuma ve değiştirme izni vermeniz gerekecektir. - -Bunun, şu nihai hedeflerle hala devam eden bir çalışma olduğunu unutmayın: - -- Yükleme sırasında geniş ana bilgisayar izinleri yoktur -- genişletilmiş izinler, her site için kullanıcı tarafından açıkça verilir. - -- Güvenilirlik ve CPU/bellek verimliliği için tamamen bildirimsel. diff --git a/platform/mv3/description/webstore.txt b/platform/mv3/description/webstore.txt index e03fa801ee7f0..ef089202b9565 100644 --- a/platform/mv3/description/webstore.txt +++ b/platform/mv3/description/webstore.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. The default ruleset corresponds to uBlock Origin's default filterset: @@ -7,24 +7,6 @@ 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 does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff --git a/platform/mv3/description/webstore.uk.txt b/platform/mv3/description/webstore.uk.txt index 799bdec1c77aa..1b77921d77b18 100644 --- a/platform/mv3/description/webstore.uk.txt +++ b/platform/mv3/description/webstore.uk.txt @@ -1,30 +1,12 @@ -uBO Lite (uBOL) - це блокувальник вмісту на основі MV3, що не потребує дозволу. +uBO Lite (uBOL) - це блокувальник вмісту на основі MV3. -Усталений набір правил відповідає типовому набору фільтрів uBlock Origin: +Набір правил за замовчанням відповідає типовому набору фільтрів uBlock Origin: - Вбудовані списки фільтрів uBlock Origin - EasyList - EasyPrivacy - Список серверів реклами та стеження від Peter Lowe -Ви можете додати більше наборів правил, перейшовши на сторінку налаштувань — натисніть на піктограму _Шестерень_ на спливній панелі. +Ви можете ввімкнути більше наборів правил, перейшовши на сторінку налаштувань — натисніть на піктограму "Перейти до панелі керування" на спливній панелі. uBOL повністю декларативний, тобто немає необхідності в постійному процесі uBOL для здійснення фільтрації, а фільтрація вмісту на основі CSS/JS-ін'єкцій надійно виконується самим браузером, а не розширенням. Це означає, що сам uBOL не споживає ресурси процесора/пам'яті під час блокування вмісту — службовий робочий процес uBOL потрібен _лише_ під час взаємодії зі спливною панеллю або сторінками опцій. - -uBOL не вимагає широкого дозволу на «читання та зміну даних» під час встановлення, отже, його можливості «з коробки» обмежені порівняно з uBlock Origin або іншими блокувальниками, які вимагають широкого дозволу на «читання/зміну даних» під час встановлення. - -Однак uBOL дозволяє вам *явно* надавати розширені дозволи на певних сайтах на ваш вибір, щоб він міг краще виконувати фільтрування на цих сайтах, використовуючи косметичну фільтрацію та вкладення скриптів. - -Щоб надати розширені дозволи на певному сайті, відкрийте спливну панель і виберіть вищий режим фільтрації, наприклад, «Оптимальний» або «Повний». - -Потім браузер попередить вас про наслідки надання додаткових дозволів, запитуваних розширенням, на поточному сайті, і ви повинні будете повідомити браузеру, чи приймаєте ви запит або відхиляєте його. - -Якщо ви приймете запит uBOL на додаткові дозволи на поточному сайті, він зможе краще фільтрувати вміст для цього сайту. - -Ви можете типовий налаштувати режим фільтрації на сторінці налаштувань uBOL. Якщо ви обираєте типовим режим Оптимальний або Повний, вам потрібно буде надати uBOL дозвіл на читання та зміну даних на всіх вебсайтах. - -Варто пам'ятати, що це досі незавершена робота з такими цілями: - -- Відсутність широких дозволів на хост під час встановлення — розширені дозволи надаються користувачем окремо для кожного сайту. - -- Повністю декларативна оцінка надійності та ефективності роботи процесора/пам'яті. diff --git a/platform/mv3/description/webstore.ur.txt b/platform/mv3/description/webstore.ur.txt index e03fa801ee7f0..2d08caf5c88f9 100644 --- a/platform/mv3/description/webstore.ur.txt +++ b/platform/mv3/description/webstore.ur.txt @@ -1,30 +1,12 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) is an MV3-based content blocker. -The default ruleset corresponds to uBlock Origin's default filterset: +ڈیفالٹ رولسیٹ 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. - -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. - -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. - -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. - -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. - -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. - -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. - -Keep in mind this is still a work in progress, with these end goals: - -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. - -- Entirely declarative for reliability and CPU/memory efficiency. diff --git a/platform/mv3/description/webstore.vi.txt b/platform/mv3/description/webstore.vi.txt index 70d6d591f7ef3..e35032cd04f4d 100644 --- a/platform/mv3/description/webstore.vi.txt +++ b/platform/mv3/description/webstore.vi.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) là trình chặn nội dung dựa trên MV3 *không-cần-cấp-phép*. +uBO Lite (uBOL) là trình chặn nội dung dựa trên MV3. Bộ quy tắc mặc định tương tự bộ lọc của uBlock Origin: @@ -7,24 +7,6 @@ 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. - -uBOL không yêu cầu cấp quyền "đọc và sửa đổi dữ liệu" chung khi cài đặt, vì vậy nên ban đầu nó sẽ hơi yếu hơn uBlock Origin hoặc các trình chặn nội dung khác mà có yêu cầu quyền "đọc và sửa đổi dữ liệu" chung khi cài đặt. - -Tuy nhiên, uBOL lại cho phép bạn cấu hình *rất cụ thể* quyền ở trên bất kỳ trang nào tự chọn của bạn, để nó có thể lọc nội dụng trên các trang đấy tốt hơn bằng các kỹ thuật như lọc hiển thị (cosmetic filtering) hay chèn kịch bản con (scriptlet injections). - -Để cấp quyền cho uBOL chặn trang bất kỳ, hãy mở cửa sổ popup và chọn một chế độ chặn cao hơn như "Tối ưu" hoặc "Hoàn toàn". - -Trình duyệt của bạn sẽ hiện cảnh báo cho việc cấp quyền cho tiện ích trên trang web hiện tại, và bạn sẽ phải chọn đồng ý hoặc từ chối yêu cầu cấp quyền. - -Nếu bạn chọn đồng ý cấp quyền cho uBOL sửa trang web bất kỳ, uBOL sẽ có thể lọc nội dung tốt hơn cho web đấy. - -Bạn cũng có thể chọn chế độ chặn mặc định ở trang cài đặt của uBOL. Nếu bạn chọn chế độ Tối ưu hoặc Hoàn toàn làm mặc định, bạn sẽ cần phải cấp quyền "đọc và sửa đổi dữ liệu" trên tất cả các trang web. - -Lưu ý rằng sản phẩm này vẫn đang trong giai đoạn phát triển, và bản hoàn thiện sẽ có những tính năng sau: - -- Không yêu cầu bất kỳ quyền nào khi cài đặt - người dùng sẽ phải tự chủ động cấp bất kỳ quyền gì cho tiện ích, cụ thể từng trang web một. - -- Hoàn toàn mang tính khai báo, để có thế chạy nhẹ hơn và ổn định hơn. diff --git a/platform/mv3/description/webstore.zh_CN.txt b/platform/mv3/description/webstore.zh_CN.txt index b307f534d48bf..aeacd9841af3c 100644 --- a/platform/mv3/description/webstore.zh_CN.txt +++ b/platform/mv3/description/webstore.zh_CN.txt @@ -1,30 +1,12 @@ -uBO Lite (uBOL) 是一个基于最新浏览器扩展接口(Manifest Version 3)打造的“无需权限”的内容屏蔽工具。 +uBO Lite (uBOL) 是一个基于最新浏览器扩展接口(Manifest Version 3)打造的的内容屏蔽工具。 该扩展预设的规则列表对应 uBlock Origin 的预设过滤规则列表: - uBlock Origin 内置过滤规则列表 - EasyList - EasyPrivacy -- Peter Lowe’s Ad and tracking server list +- Peter Lowe 的广告和跟踪服务器列表 -您可以通过设置页面添加更多过滤规则列表——点击弹出面板的“齿轮”图标。 +访问选项页面,点击弹出面板中的 _齿轮_ 图标,即可启用更多规则集。 -uBOL 的过滤规则是完全声明式的,并不需要固定保留一个 uBOL 扩展进程,基于 CSS/JS 注入的内容过滤更是交由浏览器进行调度,比起扩展本身更为可靠。 这也即是说当内容被过滤时 uBOL 自身并不占用额外 CPU 和内存资源,只有在您打开弹出面板或是设置页面时才会生成 uBOL 扩展进程。 - -uBOL 在安装时并不需要宽泛的“读取或修改网页数据”的权限,因此它的开箱即用功能相对于 uBlock Origin 以及其他安装时要求该权限的屏蔽工具显得较为有限。 - -不过,uBOL 可在您“明确”授予额外扩屏权限后,对您指定的网站采用基于 CSS/JS 注入的声明式规则加强内容过滤。 - -若要在特定网站授予扩展权限,请开启弹出面板并选择更高级的过滤模式,例如“优化”或“完全”。 - -接着浏览器会就在当前网站授予扩展额外权限有何影响示以警告,而您要接受或者拒绝该请求。 - -如果您允许 uBOL 在当前网站获取额外权限,它就可以更好地对网站内容进行过滤。 - -您还可以在 uBOL 的设置页面设定默认过滤模式。 如果设定的默认过滤模式是“优化”或“完全”,您必须授予 uBOL 读取或修改所有网页数据的权限。 - -请注意,该扩展尚未完成,其最终实现目标是: - -- 安装时不需要过多扩展权限——额外权限要由用戶指定,按需求及作用域授予。 - -- 采用完全声明式规则,以求可靠性以及更佳 CPU 和内存使用效率。 +uBOL 的过滤规则是完全声明式的,并不需要固定保留一个 uBOL 扩展进程,基于 CSS/JS 注入的内容过滤更是交由浏览器进行调度,比起扩展本身更为可靠。 这也即是说当内容被过滤时 uBOL 自身并不占用额外 CPU 和内存资源,_只有_在您打开弹出面板或是设置页面时才会生成 uBOL 扩展进程。 diff --git a/platform/mv3/description/webstore.zh_TW.txt b/platform/mv3/description/webstore.zh_TW.txt index 1add144ac7cf5..e8962a1d9aaa2 100644 --- a/platform/mv3/description/webstore.zh_TW.txt +++ b/platform/mv3/description/webstore.zh_TW.txt @@ -1,30 +1,12 @@ -uBO Lite (uBOL) 是款以 MV3 為基礎的「免權限」內容阻擋器。 +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 在安裝期間不需要氾濫的「讀取與修改資料」權限,因此它出廠時的功能和 uBlock Origin 或其他在安裝期間要求「讀取與修改資料」權限的內容阻擋程式相比,會相對受限。 - -不過 uBOL 能讓你 **明確地** 在自選的特定網站授予額外的權限,使其在這些網站的過濾效果可以在元素過濾及 scripetlet 注入的加持下得到提升。 - -若要授予指定網站延伸權限,請開啟對話框並選擇更高的過濾模式,如「最佳化」或「完整」。 - -瀏覽器接著會警告您授予擴充功能請求的額外權限會帶來的後果,而你需要告訴瀏覽器要同意還是拒絕請求。 - -如果你接受 uBOL 在目前網站請求的額外權限,其在這個網站的過濾效果將會更好。 - -您可以在 uBOL 的選項頁面設定預設的過濾模式。 如果您選擇「最佳化」或「完整」為預設的模式,您需要授予 uBOL 讀取與修改所有網站資料的權限。 - -注意這尚未完工,最終目標有: - -- 安裝期間不要有氾濫的 host 權限 —— 以網站為基準讓使用者授予延伸權限。 - -- 完全宣告式,以提升可靠性和 CPU / 記憶體效率。 +uBOL 是完全宣告式的,意即過濾過程中不需要持續性的 uBOL 處理程序參與,且以 CSS/JS 注入為基礎的內容過濾由可靠的瀏覽器執行,而非是擴充功能。 這就代表 uBOL 在內容阻擋過程不會佔用 CPU 和記憶體資源——除了和彈出面板或選項頁面互動的場景外,都不需要 uBOL 的 Service Worker 程序。 diff --git a/platform/mv3/edge/patch-extension.js b/platform/mv3/edge/patch-extension.js new file mode 100644 index 0000000000000..78e482f5cb4fe --- /dev/null +++ b/platform/mv3/edge/patch-extension.js @@ -0,0 +1,71 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2022-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import fs from 'fs/promises'; +import process from 'process'; + +/******************************************************************************/ + +const commandLineArgs = (( ) => { + const args = Object.create(null); + let name, value; + for ( const arg of process.argv.slice(2) ) { + const pos = arg.indexOf('='); + if ( pos === -1 ) { + name = arg; + value = ''; + } else { + name = arg.slice(0, pos); + value = arg.slice(pos+1); + } + args[name] = value; + } + return args; +})(); + +/******************************************************************************/ + +async function main() { + const packageDir = commandLineArgs.packageDir; + const manifestPath = `${packageDir}/manifest.json`; + + // Get manifest content + const manifest = await fs.readFile(manifestPath, { encoding: 'utf8' + }).then(text => + JSON.parse(text) + ); + + // https://learn.microsoft.com/answers/questions/918426/cant-update-extension-with-declarative-net-request + // Set all ruleset path to package root + for ( const ruleset of manifest.declarative_net_request.rule_resources ) { + const pos = ruleset.path.lastIndexOf('/'); + if ( pos === -1 ) { continue; } + ruleset.path = ruleset.path.slice(pos + 1); + } + // Commit changes + await fs.writeFile(manifestPath, + JSON.stringify(manifest, null, 2) + ); +} + +main(); + +/******************************************************************************/ diff --git a/platform/mv3/extension/_locales/ar/messages.json b/platform/mv3/extension/_locales/ar/messages.json index 6b6b476ca35f0..98f89cd6bd9d3 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": { @@ -19,8 +19,12 @@ "message": "الإعدادات", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "تطوير", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { - "message": "عن التطبيق", + "message": "حول البرنامج", "description": "appears as tab name in dashboard" }, "aboutPrivacyPolicy": { @@ -31,6 +35,14 @@ "message": "وضع التصفية", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "الإبلاغ عن مشكلة في هذا الموقع", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "افتح لوحة التحكم", "description": "English: Click to open the dashboard" @@ -48,7 +60,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,13 +111,73 @@ "message": "التبعيات الخارجية (متوافقة مع GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "مرحبا", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "معلومات استكشاف وإصلاح الأخطاء", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "لتجنب تحميل المتطوعين بتقارير مكررة، يرجى التأكد من أن المشكلة لم يتم الإبلاغ عنها بالفعل.", + "description": "A paragraph in the filter issue reporter section" + }, + "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" }, - "firstRunDescription": { - "message": "لقد قمت للتو بتثبيت uBO Lite. هنا يمكنك اختيار وضع التصفية الافتراضي لاستخدامه في جميع مواقع الويب.\n\nبشكل افتراضي ، يتم تحديد الوضع الأساسي لأنه لا يتطلب الإذن لقراءة البيانات وتعديلها. إذا كنت تثق في uBO Lite ، فيمكنك منحه إذنًا واسعًا لقراءة البيانات وتعديلها على جميع مواقع الويب من أجل تمكين المزيد من إمكانات التصفية المتقدمة لجميع مواقع الويب افتراضيًا.", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "وضع التصفية الافتراضي", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "وضع المطور", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "يمكن الوصول إلى الميزات المناسبة للمستخدمين التقنيين.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "دخول وضع تحديد العناصر السريع", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "الخروج من وضع تحديد العناصر السريع", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "عرض:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "تفاصيل وضع التصفية", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "قواعد DNR مخصصة", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "قواعد DNR لـ …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "مجموعة قواعد متغيرة", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "مجموعة قواعد جَلسة", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "حفظ", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "إرجاع", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "استيراد واضافة…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "تصدير...", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "لا تضف محتوى من مصادر غير موثوقة", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "عدد القواعد المسجلة: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/az/messages.json b/platform/mv3/extension/_locales/az/messages.json index deef8d2510f1b..ecdf3addd8418 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": { @@ -19,6 +19,10 @@ "message": "Tənzimləmələr", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Haqqında", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "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 +68,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,13 +111,73 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Xoş gəldiniz", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/be/messages.json b/platform/mv3/extension/_locales/be/messages.json index e230e07e93238..fc577d40f603a 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": { @@ -19,6 +19,10 @@ "message": "Налады", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Распрацоўка", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Пра пашырэнне", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "рэжым фільтравання", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Паведаміць пра праблему на гэтым вэб-сайце", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Адкрыць панэль кіравання", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Вонкавыя залежнасці (GPLv3-сумяшчальныя):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Вітаем", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Дыягнастычныя звесткі", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Каб не абцяжарваць добраахвотнікаў дубляванымі справаздачамі, калі ласка, пераканайцеся, што пра гэтую праблему не паведамлялі раней.", + "description": "A paragraph in the filter issue reporter section" + }, + "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" }, - "firstRunDescription": { - "message": "Вы толькі што ўсталявалі uBO Lite. Тут вы можаце выбраць прадвызначаны рэжым фільтравання для ўсіх вэб-сайтаў.\n\nКалі не ўказана іншае, выбраны базавы рэжым, бо ён не патрабуе дазволаў на чытанне і змяненне звестак. Калі вы давяраеце uBO Lite, можаце даць яму шырэйшыя дазволы на чытанне і змяненне звестак на ўсіх вэб-сайтах, каб зрабіць магчымымі больш прасунутыя функцыі фільтравання прадвызначана на ўсіх вэб-сайтах.", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "Прадвызначаны рэжым фільтравання", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Рэжым распрацоўніка", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Забяспечвае доступ да функцый, прыдатным для тэхнічных карыстальнікаў.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Перайсці ў рэжым імгненнага хавання элементаў", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Выйсці з рэжыму імгненнага хавання элементаў", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Выгляд", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Падрабязныя звесткі аб рэжыме фільтрацыі", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Уласныя правілы DNR", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Правілы у DNR", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Дынамічны набор правілаў", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Набор правілаў сеансу", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Захаваць", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Вярнуць", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Імпартаваць ды дадаць…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Экспартаваць…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Не дадавайце кантэнт з ненадзейных крыніц", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Колькасць зарэгістраваных правілаў: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/bg/messages.json b/platform/mv3/extension/_locales/bg/messages.json index f4606dd26de7d..aa05a085049f8 100644 --- a/platform/mv3/extension/_locales/bg/messages.json +++ b/platform/mv3/extension/_locales/bg/messages.json @@ -19,6 +19,10 @@ "message": "Настройки", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Разработка", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Относно", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "режим на филтриране", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "На този уебсайт", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Докладване на проблем с този уебсайт", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Табло с настройки", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Външни зависимости (съвместими с GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Добре дошли", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Информация за отстраняване на неизправности", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "За да се избегне натоварването на доброволците с дублиращи се доклади, моля, проверете дали проблемът вече не е докладван.", + "description": "A paragraph in the filter issue reporter section" + }, + "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" }, - "firstRunDescription": { - "message": "Току-що инсталирахте uBO Lite. Тук можете да изберете режима на филтриране по подразбиране, който да се използва за всички уебсайтове.\n\nПо подразбиране е избран основен режим, тъй като той не изисква разрешение за четене и промяна на данни. Ако се доверите на uBO Lite, можете да му дадете широко разрешение да чете и променя данни на всички уебсайтове, за да активирате по-разширени възможности за филтриране за всички уебсайтове по подразбиране.", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "Режим на филтриране по подразбиране", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Режим за програмисти", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Активиране на достъпа до функции, подходящи за технически потребители.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Влизане в режима на временно скриване на елемента", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Излизане от режима на временно скриване на елемента", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Създаване на персонализиран филтър", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Премахване на потребителски филтър", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Преглед:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Подробности за режима на филтриране", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Потребителски правила на DNR", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Правила на DNR за ...", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Динамичен набор от правила", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Набор от правила на сесията", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Запазване", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Връщане", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Импортиране и добавяне…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Експортиране…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Не добавяйте съдържание от ненадеждни източници", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Брой регистрирани правила: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Преместете плъзгача, за да изберете най-подходящото съответствие", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Избор", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Преглед", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Създаване", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Изберете филтър по-долу, за да маркирате съвпадащите елементи в уеб страницата. Кликнете върху кошчето, за да премахнете филтъра.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/bn/messages.json b/platform/mv3/extension/_locales/bn/messages.json index d706ab1c8592c..ffba89ed279e6 100644 --- a/platform/mv3/extension/_locales/bn/messages.json +++ b/platform/mv3/extension/_locales/bn/messages.json @@ -19,6 +19,10 @@ "message": "সেটিংস", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "সম্পর্কে", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "ফিল্টারিং মোড", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "এই ওয়েবসাইট নিয়ে সমস্যা জানাও", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "ড্যাশবোর্ড খুলুন", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "বাহ্যিক নির্ভরতা (GPLv3-সামঞ্জস্যপূর্ণ):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "স্বাগতম", - "description": "The header text for the welcome message section" + "supportS6H": { + "message": "ছাঁকনি নিয়ে সমস্যা জানাও", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "নির্দিষ্ট ছাঁকনি বিষয়ক সমস্যা এখানে জানাও uBlockOrigin/uAssets সমস্যা ট্র্যাকার. গিটহাব অ্যাকাউন্ট প্রয়োজন।", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS5H": { + "message": "সমস্যা সমাধানের তথ্য", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "একই প্রতিবেদন দুইবার এড়াতে ও স্বেচ্ছাসেবকদের বোঝা কমাতে, অনুগ্রহ করে যাচাই করো যে সমস্যাটি ইতিমধ্যে জানানো হয়নি।", + "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": "ইউবিও লাইট শনাক্ত করে", + "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" }, - "firstRunDescription": { - "message": "আপনি সবেমাত্র uBO Lite ইনস্টল করেছেন। এখানে আপনি সকল ওয়েবসাইটে ব্যবহার করার জন্য ডিফল্ট ফিল্টারিং মোড চয়ন করতে পারেন৷\n\nডিফল্টরূপে, মৌলিক মোডটি নির্বাচন করা হয়েছে কারণ এতে ডেটা পড়ার এবং পরিবর্তন করার অনুমতির প্রয়োজন হয় না৷ আপনি যদি uBO Lite-কে বিশ্বাস করেন, আপনি ডিফল্টরূপে সকল ওয়েবসাইটের জন্য আরও উন্নত ফিল্টারিং ক্ষমতা সক্ষম করার জন্য এটিকে সকল ওয়েবসাইটের ডেটা পড়তে এবং পরিবর্তন করার বিস্তৃত অনুমতি দিতে পারেন।", - "description": "Descriptive text shown at first install time only " + "supportS6Select1Option5": { + "message": "ইউবিও লাইট চালু করলে সমস্যা হয়", + "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" }, "defaultFilteringModeSectionLabel": { "message": "ডিফল্ট ফিল্টারিং মোড", @@ -147,6 +219,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" @@ -156,7 +232,147 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "ডেভেলপার মোড", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "প্রযুক্তিগত ব্যবহারকারীদের জন্য উপযুক্ত বৈশিষ্ট্যগুলিতে অ্যাক্সেস সক্ষম করুন", + "description": "Short description for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "তালিকা খুঁজো", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "পাতা অবরুদ্ধ", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "ইউবিও লাইট এই পাতা লোড হওয়া আটকিয়েছে:", + "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" + }, + "zapperTipEnter": { + "message": "এলিমেন্ট জ্যাপার মোডে প্রবেশ করুন", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "সেভ করুন", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/br_FR/messages.json b/platform/mv3/extension/_locales/br_FR/messages.json index 30395963560de..dae807915d64e 100644 --- a/platform/mv3/extension/_locales/br_FR/messages.json +++ b/platform/mv3/extension/_locales/br_FR/messages.json @@ -19,18 +19,30 @@ "message": "Arventennoù", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Diorren", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Diwar-benn", "description": "appears as tab name in dashboard" }, "aboutPrivacyPolicy": { - "message": "Politikerezh prevezded", + "message": "Politikerezh ar vuhez prevez", "description": "Link to privacy policy on GitHub (English)" }, "popupFilteringModeLabel": { "message": "mod silañ", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "War al lec'hienn-mañ", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Danevelliñ ur gudenn war al lec'hienn-mañ", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Digeriñ an daolenn-vourzh", "description": "English: Click to open the dashboard" @@ -52,11 +64,11 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupPrivacy": { - "message": "Prevezded", + "message": "Buhez prevez", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Malware domains", + "message": "Malware protection, security", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,13 +111,73 @@ "message": "Dalc'hioù diavaez (a glot gant GPLv3)", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Donemat", - "description": "The header text for the welcome message section" + "supportS6H": { + "message": "Danevelliñ ur gudenn gant ur sil", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "Danevellit kudennoù ar siloù e lec'hiennoù resis e-barzh uBlockOrigin/uAssets roll evezhiañ kudennoù. Ur c'hont GitHub zo rekis.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS5H": { + "message": "Titouroù diagnostikañ kudennoù", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Evit nompas sammañ ar genlabourerien a-youl vat gant meur a zanevell heñvel, gwiriit ma n'eo ket bet danevellet ho kudenn en a-raok mar plij. Notenn: ma klikit ar bouton e vo kaset anv herberc'hier ar bajenn da c'h-GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "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 ar vuhez prevez he deus", + "description": "An entry in the widget used to select the type of issue" }, - "firstRunDescription": { - "message": "Emaoc'h o paouez staliañ uBO Lite. Amañ-dindan e c'hallit dibab ar mod silañ dre ziouer evit an holl lec'hiennoù.\n\nDre ziouer eo bet dibabet ar mod diazez peogwir n'eus ket ezhomm reiñ aotre da lenn ha kemmañ roadennoù da uBO Lite. M'ho peus fiziañs e uBO Lite e c'hallit reiñ aotreoù ouzhpenn dezhañ a-benn lenn ha kemmañ roadennoù en holl lec'hiennoù, mod-se e vo enaouet ar mod silañ araokaet en holl lec'hiennoù dre ziouer.", - "description": "Descriptive text shown at first install time only " + "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": "Kas a ra da veziantoù droukyoulet pe d'an higennañ niverel", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "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" }, "defaultFilteringModeSectionLabel": { "message": "Mod silañ dre ziouer", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Mod diorroer", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Gweredekaat a ra ar fonksionelezhioù azasaet d'an implijerien deknikel.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Mont er mod \"dilemel elfennoù\"", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Kuitaat ar mod \"dilemel elfennoù\"", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Krouiñ ur sil personelaet", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Lemel ur sil personelaet", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Gwelet:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Munudoù ar mod silañ", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Reolennoù DNR personelaet", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Reolennoù DNR eus …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Hollad reolennoù dinamek", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Hollad reolennoù an estez", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Enrollañ", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Nullañ", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Enporzhiañ hag ouzhpennañ", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Ezporzhiañ", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Arabat ouzhpennañ danvez a zeu diouzh mammennoù douetus.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Niver a reolennoù marilhet: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Dibunit ar reti evit diuzañ ar pezh a glot ar muiañ", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Diuzañ", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Rakwel", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Krouiñ", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Diuzit ur sil amañ-dindan evit sklêrijennañ an elfennoù kendere er bajenn web. Klikit ar pod-lastez evit lemel ur sil.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/bs/messages.json b/platform/mv3/extension/_locales/bs/messages.json index ab768f6b72003..04793c0162846 100644 --- a/platform/mv3/extension/_locales/bs/messages.json +++ b/platform/mv3/extension/_locales/bs/messages.json @@ -19,6 +19,10 @@ "message": "Postavke", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "O aplikaciji", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "način filtriranja", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Otvorite nadzornu ploču", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Vanjske ovisnosti (kompatibilno s GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Dobrodošli", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "Upravo ste instalirali uBO Lite. Ovdje možete odabrati zadani način filtriranja koji će se koristiti na svim web stranicama.\n\nPrema zadanim postavkama, Osnovni način rada je odabran jer ne zahtijeva dozvolu za čitanje i izmjenu podataka. Ako vjerujete uBO Lite-u, možete mu dati široku dozvolu za čitanje i izmjenu podataka na svim web lokacijama kako bi se omogućile naprednije mogućnosti filtriranja za sve web stranice prema zadanim postavkama.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Zadani način filtriranja", @@ -147,6 +219,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 +232,147 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/ca/messages.json b/platform/mv3/extension/_locales/ca/messages.json index 5e1f1eb9c7d60..2dd5fdda9822a 100644 --- a/platform/mv3/extension/_locales/ca/messages.json +++ b/platform/mv3/extension/_locales/ca/messages.json @@ -19,6 +19,10 @@ "message": "Configuració", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Desenvolupament", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Quant a", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "mode de filtre", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "En aquest lloc web", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Informa d'un problema en aquest lloc web", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Obre el tauler", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Dependències externes (compatibles amb GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Us donem la benvinguda", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Informació de resolució de problemes", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Per a evitar la sobrecàrrega del nostre voluntariat amb informes duplicats, verifiqueu abans que el problema encara no s'ha notificat. Nota: En fer clic, enviareu la pàgina causant al nostre GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "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" }, - "firstRunDescription": { - "message": "Acabeu d'instal·lar l'uBO Lite. Aquí podeu triar el mode de filtrat per defecte per utilitzar-lo a tots els llocs web.\n\nPer defecte, el mode Bàsic està seleccionat perquè no requereix permís per llegir i canviar dades. Si confieu en l'uBO Lite, podeu donar-li un ampli permís per llegir i canviar dades a tots els llocs web per tal d'activar capacitats de filtratge més avançades per a tots els llocs web per defecete.", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "Mode de filtratge per defecte", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Mode de desenvolupador", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Habilita l'accés a funcions adequades per a usuaris tècnics.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Accedeix al mode d'eliminació d'elements", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Surt del mode d'eliminació d'elements", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Crea un filtre personalitzat", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Elimina un filtre personalitzat", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Vista:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Detalls del mode de filtratge", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Regles DNR personalitzades", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Regles DNR de…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Conjunt de regles dinàmiques", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Conjunt de regles de sessió", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Desa", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Restaura", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Importa i annexa…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exporta…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "No afegiu contingut de fonts no fiables", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Nombre de regles registrades: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Moveu el control lliscant per a seleccionar la millor coincidència", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Selecciona", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Previsualitza", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Crea", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Seleccioneu un filtre a continuació per a ressaltar els elements coincidents de la pàgina web. Feu clic a la paperera per a eliminar un filtre.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/cs/messages.json b/platform/mv3/extension/_locales/cs/messages.json index db051f05d1ad1..24460eb06a27a 100644 --- a/platform/mv3/extension/_locales/cs/messages.json +++ b/platform/mv3/extension/_locales/cs/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Blokátor obsahu vyžadující méně oprávnění. Blokuje reklamy, sledovače, těžaře a jiné ihned po instalaci.", + "message": "Účinný blokátor obsahu. Okamžitě po instalaci blokuje reklamy, sledovače, těžaře a další.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Nastavení", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Vývoj", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "O rozšíření", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "Filtrovací režim", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Na této webové stránce", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Nahlásit problém na této webové stránce", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Otevřít ovládací panel", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Externí závislosti (kompatibilní s GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Vítejte", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Informace o řešení problémů", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Abyste dobrovolníky nezatěžovali duplicitními hlášeními, ověřte si, zda již problém nebyl nahlášen.", + "description": "A paragraph in the filter issue reporter section" + }, + "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" }, - "firstRunDescription": { - "message": "Právě jste nainstalovali uBO Lite. Zde si můžete vybrat výchozí režim filtrování pro použití na všech webových stránkách.\n\nVe výchozím nastavení je vybrán režim Základní, protože nevyžaduje oprávnění ke čtení a změně dat. Pokud důvěřujete uBO Lite, můžete mu udělit široké oprávnění číst a měnit data na všech webových stránkách, abyste ve výchozím nastavení povolili pokročilejší možnosti filtrování pro všechny webové stránky.", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "Výchozí filtrovací režim", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Vývojářský režim", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Umožňuje přístup k funkcím vhodným pro technicky zdatné uživatele.", + "description": "Short description for a checkbox in the options page" + }, + "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 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" + }, + "zapperTipEnter": { + "message": "Přejít do režimu dočasného skrytí prvků", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Opustit režim dočasného skrytí prvků", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Vytvořit vlastní filtr", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Odebrat vlastní filtr", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Zobrazit:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Detaily filtovacího módu", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Vlastní pravidla DNR", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR pravidla …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamický seznam pravidel", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Uložit", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Vrátit", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Importovat a připojit…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exportovat…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Nepřidávat filtry z nedůvěryhodných zdrojů", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Počet registrovaných pravidel: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Posunutím jezdce vyberte nejlepší shodu", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Vybrat", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Náhled", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Vytvořit", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Výběrem níže uvedeného filtru zvýrazníte odpovídající prvky na webové stránce. Kliknutím na koš filtr odstraníte.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/cv/messages.json b/platform/mv3/extension/_locales/cv/messages.json index 4bbb5e389bf08..ef4d2656fc21e 100644 --- a/platform/mv3/extension/_locales/cv/messages.json +++ b/platform/mv3/extension/_locales/cv/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": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +68,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,13 +111,73 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/cy/messages.json b/platform/mv3/extension/_locales/cy/messages.json index c9d0e36583d83..94426574a93a5 100644 --- a/platform/mv3/extension/_locales/cy/messages.json +++ b/platform/mv3/extension/_locales/cy/messages.json @@ -12,13 +12,17 @@ "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": { "message": "Gosodiadau", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Datblygu", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Ynghylch", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "modd hidlo", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "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 +56,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 +68,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,13 +111,73 @@ "message": "Gofynion allanol (cydnaws â GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Croeso", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Dod o hyd i adroddiadau tebyg ar GitHub", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Cyfeiriad y dudalen we:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Y dudalen we…", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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": "Yn ôl", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Cau'r ffenestr hon", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Peidio â'm rhybuddio eto am y wefan hon", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Parhau", + "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Galluogi'r modd saethu elfen", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Gadael y modd saethu elfen", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Cadw", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/da/messages.json b/platform/mv3/extension/_locales/da/messages.json index ae494fe74a254..119eebf8cd60c 100644 --- a/platform/mv3/extension/_locales/da/messages.json +++ b/platform/mv3/extension/_locales/da/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "En tilladelsesløs indholdsblocker. Blokerer som standard annoncer, trackere, minere mv. straks efter installationen.", + "message": "En effektiv indholdsblocker. Blokerer annoncer, trackere, minere mm. umiddelbart efter installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Indstillinger", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Udvikl", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Om", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtreringstilstand", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "På dette websted", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Anmeld et problem på dette websted", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Åbn kontrolpanelet", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Eksterne afhængigheder (GPLv3-kompatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Velkommen", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Fejlfindingsinformation", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "For at undgå at bebyrde frivillige med dubletanmeldelser, så tjek venligst, at problematikken ikke allerede er anmeldt. Bemærk: Ved at klikke på knappen, sendes sidens oprindelse til GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find lign. anmeldelser på GitHub", + "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" }, - "firstRunDescription": { - "message": "Du har netop installeret uBO Lite. Her kan den standardfiltreringstilstand vælges, der skal bruges på alle websteder.\n\nStandardvalget er Basis-tilstand, da den ikke kræver tilladelse til at læse og ændre data. Er uBO Lite betroet, kan den udvidede tilladelse til at læse og ændre data på alle websteder tildeles for som standard at aktivere mere avancerede filtreringsfunktioner for alle websteder.", - "description": "Descriptive text shown at first install time only " + "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 på GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Standardfiltreringstilstand", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Udviklertilstand", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Aktiverer adgang til funktioner egnede for tekniske brugere.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Gå til elementdræber­tilstand", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Forlad elementdræber­tilstand", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Opret et tilpasset filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Fjern et tilpasset filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Vis:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtreringstilstandsdetaljer", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Tilpassede DNR-regler", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR-regler for…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamiske regelsæt", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Sessionsregelsæt", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Gem", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Tilbagefør", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Importér og tilføj…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Eksportér…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Tilføj ikke indhold fra ikke-betroede kilder.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Antal registrerede regler : {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Flyt skyderen for at vælge det bedste match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Vælg", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Forhåndsvisning", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Opret", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Vælg et filter nedenfor for at fremhæve matchende elementer på websiden. Klik på papirkurven for at fjerne et filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/de/messages.json b/platform/mv3/extension/_locales/de/messages.json index 13829f3e919fb..8c77f5ad1a1d2 100644 --- a/platform/mv3/extension/_locales/de/messages.json +++ b/platform/mv3/extension/_locales/de/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Ein Inhaltsblocker, der ohne Berechtigungen auskommt. Blockiert Werbung, Tracker und mehr sofort nach der Installation.", + "message": "Ein effizienter Inhaltsblocker. Blockiert Werbung, Tracker und mehr sofort nach der Installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Einstellungen", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Entwickeln", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Über", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "Filtermodus", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Auf dieser Website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Ein Problem melden", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Dashboard öffnen", "description": "English: Click to open the dashboard" @@ -56,7 +68,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,13 +111,73 @@ "message": "Externe Abhängigkeiten (GPLv3-kompatibel):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Willkommen", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Informationen zur Fehlerbehebung", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Um die Freiwilligen nicht mit doppelten Meldungen zu überlasten, vergewissern Sie sich bitte, dass das Problem noch nicht gemeldet wurde. Hinweis: Das Anklicken der Schaltfläche übermittelt den Ursprung der Seite an GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Ähnliche Meldungen auf GitHub 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" }, - "firstRunDescription": { - "message": "Sie haben soeben uBO Lite installiert. Sie können hier den Standardfiltermodus auswählen, der auf allen Websites angewendet werden soll.\n\nStandardmäßig ist der einfache Modus ausgewählt, weil er keine Berechtigung zum Lesen und Ändern von Daten erfordert. Wenn Sie uBO Lite vertrauen, können Sie dieser Erweiterung eine weitreichende Berechtigung zum Lesen und Ändern von Daten auf allen Websites erteilen, um standardmäßig erweiterte Filterfunktionen für alle Websites zu aktivieren.", - "description": "Descriptive text shown at first install time only " + "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 auf GitHub erstellen", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Standardfiltermodus", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Entwicklermodus", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Ermöglicht den Zugriff auf Funktionen, die für technisch Versierte bestimmt sind.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Ein Element entfernen", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Temporären Modus beenden", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Eigenen Filter erstellen", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Eigenen Filter entfernen", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Ansicht:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Details zum Filtermodus", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Eigene DNR-Regeln", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR-Regeln von …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamische Regeln", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Regeln der aktuellen Sitzung", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Speichern", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Rückgängig machen", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Importieren und ergänzen …", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exportieren …", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Verwenden Sie keine Regeln aus unseriösen Quellen", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Anzahl erfasster Regeln: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Schieberegler bewegen, um die beste Übereinstimmung auszuwählen", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Auswählen", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Vorschau", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Erstellen", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Das Auswählen eines unten stehenden Filters hebt übereinstimmende Elemente auf der Webseite hervor. Auf den Mülleimer klicken, um einen Filter zu entfernen.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/el/messages.json b/platform/mv3/extension/_locales/el/messages.json index 8e3bc5ed1fe52..e57d6bd76fe8b 100644 --- a/platform/mv3/extension/_locales/el/messages.json +++ b/platform/mv3/extension/_locales/el/messages.json @@ -19,6 +19,10 @@ "message": "Ρυθμίσεις", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Ανάπτυξη", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Σχετικά", "description": "appears as tab name in dashboard" @@ -31,8 +35,16 @@ "message": "λειτουργία φιλτραρίσματος", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Για αυτόν τον ιστότοπο", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Αναφορά ενός ζητήματος σε αυτόν τον ιστότοπο", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { - "message": "Ανοίξτε τον πίνακα ελέγχου", + "message": "Άνοιγμα του πίνακα εργαλείων", "description": "English: Click to open the dashboard" }, "popupMoreButton": { @@ -99,13 +111,73 @@ "message": "Εξωτερικές εξαρτήσεις (συμβατές με GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Καλώς ήρθατε", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Πληροφορίες για αντιμετώπιση προβλημάτων", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Για να μην επιβαρυνθούν οι εθελοντών με διπλές αναφορές, βεβαιωθείτε ότι το ζήτημα δεν έχει ήδη αναφερθεί.Σημείωση: Με το πάτημα του κουμπιού, θα σταλεί η σελίδα προέλευσης στο GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Βρείτε παρόμοιες αναφορές στο GitHub", + "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" }, - "firstRunDescription": { - "message": "Μόλις εγκαταστήσατε το uBO Lite. Μπορείτε να επιλέξετε εδώ την προεπιλεγμένη λειτουργία φιλτραρίσματος για χρήση σε όλους τους ιστότοπους.\n\nΑπό προεπιλογή, έχει επιλεγεί η λειτουργία Βασική επειδή δεν απαιτεί άδεια ανάγνωσης και αλλαγής δεδομένων. Εάν εμπιστεύεστε το uBO Lite, μπορείτε να του δώσετε ευρεία άδεια να διαβάζει και να αλλάζει δεδομένα σε όλους τους ιστότοπους, προκειμένου να ενεργοποιηθούν πιο προηγμένες δυνατότητες φιλτραρίσματος για όλους τους ιστότοπους από προεπιλογή.", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "Προεπιλεγμένη λειτουργία φιλτραρίσματος", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Λειτουργία προγραμματιστή", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Ενεργοποίηση πρόσβασης σε δυνατότητες κατάλληλες για τεχνικούς χρήστες.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Είσοδος σε λειτουργία αφαίρεσης στοιχείων", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Έξοδος από λειτουργία αφαίρεσης στοιχείων", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Δημιουργία προσαρμοσμένου φίλτρου", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Αφαίρεση προσαρμοσμένου φίλτρου", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Προβολή:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Λεπτομέρειες λειτουργίας φιλτραρίσματος", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Προσαρμοσμένοι κανόνες DNR", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Κανόνες DNR του …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Σετ κανόνων που είναι δυναμικοί", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Σετ κανόνων για τη συνέδρεια", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Αποθήκευση", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Επαναφορά", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Εισαγωγή και προσθήκη…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Εξαγωγή…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Να μην προστίθενται περιεχόμενο από μη αξιόπιστες πηγές.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Σύνολο εγγεγραμμένων κανόνων: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Μετακινήστε το ρυθμιστικό για να επιλέξετε την καλύτερη αντιστοίχιση", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Επιλογή", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Προεπισκόπηση", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Δημιουργία", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Επιλέξτε ένα φίλτρο παρακάτω για να επισημάνετε τα στοιχεία που αντιστοιχούν στην ιστοσελίδα. Κάντε κλικ στον κάδο απορριμμάτων για να αφαιρέσετε ένα φίλτρο.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/en/messages.json b/platform/mv3/extension/_locales/en/messages.json index 878f3cc80b78c..cc004b90c454f 100644 --- a/platform/mv3/extension/_locales/en/messages.json +++ b/platform/mv3/extension/_locales/en/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": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +68,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,13 +111,73 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/en_GB/messages.json b/platform/mv3/extension/_locales/en_GB/messages.json index 884d7c1960243..479f72114c6da 100644 --- a/platform/mv3/extension/_locales/en_GB/messages.json +++ b/platform/mv3/extension/_locales/en_GB/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "An experimental, permission-less content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", + "message": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue on this website", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enable access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Enter element zapper mode", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the dustbin to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/eo/messages.json b/platform/mv3/extension/_locales/eo/messages.json index ba5cfde43e504..4f00c482cbd28 100644 --- a/platform/mv3/extension/_locales/eo/messages.json +++ b/platform/mv3/extension/_locales/eo/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": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Agordoj", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Pri", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +68,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,13 +111,73 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Bonvenon", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/es/messages.json b/platform/mv3/extension/_locales/es/messages.json index 53ff70b95a657..e0ffbdf5af0b5 100644 --- a/platform/mv3/extension/_locales/es/messages.json +++ b/platform/mv3/extension/_locales/es/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Un bloqueador de contenido con menos permisos. Bloquea anuncios, rastreadores, criptomineros y aún más.", + "message": "Un bloqueador de contenido eficiente. Bloquea anuncios, rastreadores, criptomineros y aún más.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Configuración", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Desarrollo", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Acerca de", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "modo de filtrado", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "En este sitio web", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Reportar un problema", + "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 +68,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,13 +111,73 @@ "message": "Dependencias externas (compatibles con GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Bienvenida", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Información para solucionar problemas", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Para evitar sobrecargar a voluntarios con reportes duplicados, verifica que el problema no haya sido reportado. Nota: al hacer clic en el botón, hará que el origen de la página se envíe a GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Encontrar reportes similares en GitHub", + "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" }, - "firstRunDescription": { - "message": "Acabas de instalar uBO Lite. Aquí puedes elegir el modo de filtrado predeterminado que se utilizará en todos los sitios web.\n\nPor defecto, el modo básico está seleccionado porque no requiere permiso para leer y modificar datos. Si confías en uBO Lite, puedes otorgarle un permiso amplio para leer y modificar datos en todos los sitios web para habilitar capacidades de filtrado más avanzadas para todos los sitios web de forma predeterminada.", - "description": "Descriptive text shown at first install time only " + "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 en GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Modo de filtrado predeterminado", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Modo desarrollador", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Habilita acceso a características aptas para usuarios técnicos.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Eliminar un elemento", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Salir del modo eliminación de elementos", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Crear un filtro personalizado", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Eliminar un filtro personalizado", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Ver:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Detalles del modo de filtrado", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Reglas DNR personalizadas", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Reglas DNR de …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Conjunto de reglas dinámicas", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Conjunto de reglas de sesión", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Guardar", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revertir", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Importar y anexar…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exportar…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "No añadas contenido de fuentes no confiables", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Número de reglas registradas: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Mueve el control deslizante para seleccionar la mejor coincidencia", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Elegir", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Vista previa", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Crear", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Selecciona un filtro abajo para resaltar los elementos coincidentes en la página web. Haz clic en la papelera para eliminar un filtro.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/et/messages.json b/platform/mv3/extension/_locales/et/messages.json index 69f6aa21932e4..55c93d8a2334e 100644 --- a/platform/mv3/extension/_locales/et/messages.json +++ b/platform/mv3/extension/_locales/et/messages.json @@ -19,6 +19,10 @@ "message": "Sätted", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Arendajale", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Teave", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtreerimisrežiim", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Sellel veebilehel", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Teavita veast", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Ava töölaud", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Välised sõltuvused (ühilduvad GPLv3-ga):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Tere tulemast", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Tõrkeotsingu teave", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Vabatahtlike koormamise vältimiseks samade teadetega veenduge, et keegi pole selle murega juba varem pöördunud. Märge! Nupule klõpsamisega saadetakse GitHubile lehekülje aadress.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Leia GitHubist sarnaseid aruandeid", + "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" }, - "firstRunDescription": { - "message": "Olete paigaldanud uBO Lite'i. Nüüd valige kõigil veebilehtedel kasutatav üldine filtreerimisrežiim.\n\nTavaliselt kehtib Põhiline režiim, kuna see ei vaja andmete lugemise ja muutmise luba. uBO Lite'i usaldamisel saate sel lubada andmeid lugeda ja muuta kõigil veebilehtedel, et neid saaks vaikimisi filtreerida põhjalikumalt.", - "description": "Descriptive text shown at first install time only " + "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 GitHubis uus aruanne", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Tavaline filtreerimisrežiim", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Arendaja režiim", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Luba juurdepääs tehnilise taibuga kasutajatele mõeldud võimalustele.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Eemalda element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Välju elemendi hävitusrežiimist", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Loo ise filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Eemalda enda filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Vaade:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtreerimisrežiimi andmed", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Enda aadressiresolverite avastamise reeglid", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Aadressiresolverite avastamise reeglid sellelt …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dünaamiline reeglitekogumik", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Seansi reeglitekogumik", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Salvesta", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Taasta", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Impordi ja lisa…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Ekspordi…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Lisa sisu vaid usaldusväärsetest allikatest", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Registreeritud reeglite arv: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Parima tulemuse saavutamiseks liigutage liugurit", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Vali", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Eelvaade", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Loo", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Valige allolev filter, et tõsta esile veebilehel kattuvad elemendid. Filtri eemaldamiseks klõpsake prügikasti.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/eu/messages.json b/platform/mv3/extension/_locales/eu/messages.json index 353f3b79c3eed..89935cc4a9776 100644 --- a/platform/mv3/extension/_locales/eu/messages.json +++ b/platform/mv3/extension/_locales/eu/messages.json @@ -19,6 +19,10 @@ "message": "Ezarpenak", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Honi buruz", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "Iragazteko modua", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Webgune honetan arazo baten berri eman", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Ireki lan-lekua", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Kanpo menpekotasunak (GPLv3 lizentziarekin bateragarriak):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Ongi etorri", - "description": "The header text for the welcome message section" + "supportS6H": { + "message": "iragazkiko arazo baten berria eman", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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": "uBO Lite detektatzen da", + "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" }, - "firstRunDescription": { - "message": "uBO Lite instalatu berri duzu. Hemen, webgune guztietan erabiltzeko iragazteko modu lehenetsia hauta dezakezu.\n\nAurrez zehaztuta, Oinarrizkoa modua hautatzen da, ez baita baimenik behar datuak irakurtzeko eta aldatzeko. uBO Lite-n konfiantza baduzu, webgune guztietan datuak irakurtzeko eta aldatzeko baimen zabala eman dezakezu, webgune guztietarako iragazteko gaitasun aurreratuagoak gaitzeko, aldez aurretik zehaztuta.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Lehenetsitako iragazteko modua", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Find lists", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Blokeatutako orrialdea", + "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": "parametrorik gabe", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Joan atzera", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Itxi leiho hau", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Ez esan ezer berriz ere orrialde honi buruz", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Aurrera", + "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Sartu elementua zapper moduan", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Irten elementua zapper moduan", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/fa/messages.json b/platform/mv3/extension/_locales/fa/messages.json index a18a6ed3a7cb3..1e76b43f95481 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": { @@ -19,6 +19,10 @@ "message": "تنظیمات", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "درباره", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "باز کردن داشبورد", "description": "English: Click to open the dashboard" @@ -56,7 +68,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 +92,7 @@ "description": "English: Source code (GPLv3)" }, "aboutContributors": { - "message": "Contributors", + "message": "شرکت کنندگان", "description": "English: Contributors" }, "aboutSourceCode": { @@ -99,13 +111,73 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/fi/messages.json b/platform/mv3/extension/_locales/fi/messages.json index 05d42117aa0ed..a3eb292769a25 100644 --- a/platform/mv3/extension/_locales/fi/messages.json +++ b/platform/mv3/extension/_locales/fi/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Käyttöoikeudeton estotyökalu, joka estää välittömästi asennuksesta lähtien mm. mainokset, seurannat ja kryptolouhijat.", + "message": "Tehokas estotyökalu, joka estää heti asennuksen jälkeen mm. mainokset, seurannat ja kryptolouhijat.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Asetukset", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Kehittäjille", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Tietoja", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "suodatustila", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "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,13 +111,73 @@ "message": "Ulkopuoliset riippuvuudet (GPLv3-yhteensopiva):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Tervetuloa", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Vianselvitystiedot", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Välttääksesi vapaaehtoisten kuormittamisen ylimääräisillä ilmoituksilla, tarkasta ensin onko ongelmasta jo ilmoitettu. Huomioi: Painikkeen painallus lähettää sivun osoitteen GitHubiin.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Etsi GitHubista vastaavia 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" }, - "firstRunDescription": { - "message": "Olet juuri asentanut uBO Liten. Tästä voit valita kaikilla sivustoilla oletusarvoisesti käytettävän suodatustilan.\n\nOletusarvoinen valinta on Perus-tila, koska se ei vaadi tietojen luku- ja muokkausoikeutta. Jos luotat uBO Liteen, voit myöntää sille kaikki sivustot kattavan laajan tietojen luku- ja muokkausoikeuden, jolloin edistyneemmät suodatusominaisuudet ovat oletusarvoisesti käytössä kaikilla sivustoilla.", - "description": "Descriptive text shown at first install time only " + "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 GitHubiin uusi ilmoitus", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Oletusarvoinen suodatustila", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Kehittäjätila", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Aktivoi teknisille käyttäjille suunnatut ominaisuudet.", + "description": "Short description for a checkbox in the options page" + }, + "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": "parametritön", + "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" + }, + "zapperTipEnter": { + "message": "Avaa elementtien piilotustila", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Poistu elementtien piilotustilasta", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Tallenna", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Palauta", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Tuo ja lisää…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Vie…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Rekisteröityjen sääntöjen määrä: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/fil/messages.json b/platform/mv3/extension/_locales/fil/messages.json index fe5daa48fba7e..7ed7711d13702 100644 --- a/platform/mv3/extension/_locales/fil/messages.json +++ b/platform/mv3/extension/_locales/fil/messages.json @@ -19,6 +19,10 @@ "message": "Mga Setting", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Bumuo", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Tungkol", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "moda nang pagsasala", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Magulat ng problema sa website na ito", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Buksan ang dashboard", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Mga panlabas na dependency (angkop sa GPLv3)", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Mabuhay", - "description": "The header text for the welcome message section" + "supportS6H": { + "message": "Magulat ng problema sa filter ", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "Magreklamo dito ng mga isyu sa filter sa mga website: uBlockOrigin/uAssets issue tracker. Nangangailangan ng account sa GitHub.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS5H": { + "message": "Inpormasyon para sa troubleshooting", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Upang hindi makagambala ng mga volunteer sa mga umuulit na ulat, pakisigurado na hindi pa narereklamo ang iyong isyu. Paalala: Mapapadala sa Github ang origin ng page na ito pagpindot dito.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Maghanap ng katulad ng ulat sa GitHub", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Lokasyon ng webpage:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Ang webpage", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Mamili --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Nagpapakita ng ads o mga bakas ng ads", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "May mga overlay o iba pang harang", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Nakadedetect ng uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "May mga isyu sa privacy", + "description": "An entry in the widget used to select the type of issue" }, - "firstRunDescription": { - "message": "Maligayang pagdating sa uBO Lite. Dito mo mapipili ang default na mode sa pagfi-filter para sa lahat ng mga website.\n\nAng default na mode ay Basic dahil hindi nito kailangan ng karagdagang pahintulot na magbasa at magbago ng datos. Pwede mong pahintulutan ang uBO Lite, kung nagtitiwala ka sa amin, na basahin at baguhin ang data ng lahat ng mga website para sa karagdagang kakayahan sa pagfi-filter.", - "description": "Descriptive text shown at first install time only " + "supportS6Select1Option5": { + "message": "Hindi gumagana nang maayos kapag nakabukas ang uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Nagbubukas ng mga hindi kailangang tab o window", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Patungo sa badware o phishing", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Markahan ang webpage na \"NSFW\" (“Not Safe For Work”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Gumawa ng bagong ulat sa Github", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Default na mode sa pagfi-filter", @@ -144,9 +216,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place.", + "message": "Listahan ng mga website kung saan walang magagawang filtering. ", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[hostnames lamang]\nexample.com\ngames.example \n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { "message": "Ugali", "description": "The header text for the 'Behavior' section" @@ -156,7 +232,147 @@ "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { - "message": "Show the number of blocked requests on the toolbar icon", + "message": "Ipakita ang dami ng napigilang mga request sa toolbar na icon", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Paganahin ang striktong pagharang", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Haharangan ang pagpunta sa mga hindi nais na mga site, at bibigyan ka ng pagkakataon na magpatuloy.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Nagbibigay ng mga katangian para sa mga teknikal na gumagamit.", + "description": "Short description for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Maghanap ng mga listahan", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Nakaharang na page", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "Hindi pinayagan ng uBO Lite ang pagpunta sa page dahil:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Hinarang ang page na ito dahil sa isang filter sa {{listname}}", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "Nais magpatuloy ng page na ito sa isa pang site. Kung magpapatuloy ka, dadalhin ka sa: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "walang mga parameter", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Bumalik", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Isara ang window na ito", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Huwag mo na akong balaan tungkol sa site na ito", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Magpatuloy", + "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Paganahin ang element zapper mode", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Umalis sa element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "I-save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Ibalik", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "I-import at idagdag...", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "I-export...", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Dami ng mga nakaregister na patakaran: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/fr/messages.json b/platform/mv3/extension/_locales/fr/messages.json index 0152c8e9139c3..d924fcd03be8b 100644 --- a/platform/mv3/extension/_locales/fr/messages.json +++ b/platform/mv3/extension/_locales/fr/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Un bloqueur de contenu sans permission requise. Bloque les publicités, pisteurs, mineurs et plus dès l'installation.", + "message": "Un bloqueur de contenu efficace. Bloque les publicités, pisteurs, mineurs et plus dès l'installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Paramètres", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Développement", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "À propos", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "Mode de filtrage", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Sur ce site Web", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Rapporter un problème", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Ouvrir le Tableau de bord", "description": "English: Click to open the dashboard" @@ -56,7 +68,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Domaines malveillants", + "message": "Protection contre les logiciels malveillants, sécurité", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,13 +111,73 @@ "message": "Dépendances externes (compatibles GPLv3) :", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Bienvenue", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Informations de dépannage", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Pour éviter d'encombrer les contributeurs avec des rapports en double, veuillez vérifier que le problème n'a pas déjà été rapporté.\nNote : Cliquer sur le bouton entraînera l'envoi de la page d'origine à GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Trouver des rapports similaires sur GitHub", + "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" }, - "firstRunDescription": { - "message": "Vous venez d'installer uBO Lite. À présent vous pouvez choisir le mode de filtrage par défaut à utiliser sur tous les sites Web.\n\nPar défaut, le mode Basique est sélectionné car il ne requiert pas de permissions pour lire et modifier les données. Si vous faites confiance à uBO Lite, vous pouvez lui donner des permissions étendues pour lire et modifier les données sur tous les sites Web pour activer des capacités de filtrage plus avancées pour tous les sites Web par défaut.", - "description": "Descriptive text shown at first install time only " + "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 sur GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Mode de filtrage par défaut", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Mode développeur", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Active l'accès aux fonctionnalités adaptées aux utilisateurs techniques.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Supprimer un élément", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Quitter le mode Zappeur d'élément", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Créer un filtre personnalisé", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Supprimer un filtre personnalisé", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Vue :", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Détails du mode de filtrage", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Règles DNR personnalisées", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Règles DNR de ", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Règles dynamiques", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Règles de session", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Enregistrer", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Rétablir", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Importer", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exporter", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Ne pas ajouter de contenu provenant de sources non fiables", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Nombre de règles enregistrées : {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Déplacez le curseur pour sélectionner la meilleure correspondance", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Cibler", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Aperçu", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Créer", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Choisissez un filtre ci-dessous pour surligner les éléments correspondants dans la page Web. Cliquez sur l'icône de poubelle pour supprimer un filtre.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/fy/messages.json b/platform/mv3/extension/_locales/fy/messages.json index f583e4b49e1c1..2486ff197d004 100644 --- a/platform/mv3/extension/_locales/fy/messages.json +++ b/platform/mv3/extension/_locales/fy/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "In eksperimintele, tastimmingsleaze ynhâldsblokkearder. Blokkearret daliks nei ynstallaasje advertinsjes, trackers, miners en mear.", + "message": "In, tastimmingsleaze ynhâldsblokkearder. Blokkearret daliks nei ynstallaasje advertinsjes, trackers, miners en mear.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Ynstellingen", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Untwikkelje", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Oer", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtermodus", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Op dizze website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "In probleem melde", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Dashboerd iepenje", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Eksterne ôfhinklikheden (GPLv3-kompatibel):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Wolkom", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Probleemoplossingsynformaasje", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Kontrolearje oft it probleem net earder meld is om foar te kommen dat frijwilligers mei dûbele meldingen belêst wurde.", + "description": "A paragraph in the filter issue reporter section" + }, + "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" }, - "firstRunDescription": { - "message": "Jo hawwe sakrekt uBO Lite ynstallearre. Hjir kinne jo de standery filtermodus foar it gebrûk op alle websites kieze.\n\nStandert wurdt de modus Basis selektearre, omdat hjirfoar gjin tastimming foar it lêzen en wizigjen fan gegevens fereaske is. As jo uBO Lite fertrouwe, kinne jo it brede tastimming foar it lêzen en wizigjen fan gegevens op alle websites ferliene, sadat standert mear avansearre filtermooglikheden foar alle websites beskikber binne.", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "Standert filtermodus", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Untwikkelersmodus", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Skeakelet tagong ta foar technyske brûkers geskikte funksjes yn.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "In elemint­ fuortsmite", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Elemint­wisker­modus slute", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "In oanpast filter meitsje", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "In oanpast filter fuortsmite", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Werjefte:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Details fan filtermodus", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Oanpaste DNR-regels", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR-regels fan …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamyske regelset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Sesjeregelset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Bewarje", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Ungedien meitsje", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Ymportearje en tafoegje…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Eksportearje…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Foegje gjin ynhâld fan net-fertroude boarnen ta.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Oantal registrearre regels: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Ferpleats de skowregeler foar de beste oerienkomst", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Kieze", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Foarbyld", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Oanmeitsje", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Selektearje hjirûnder in filter om oerienkommende eleminten yn de webside te markearjen. Klik op it jiskefet om in filter fuort te smiten.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/gl/messages.json b/platform/mv3/extension/_locales/gl/messages.json index 760c65c899a85..b13f61beaddcb 100644 --- a/platform/mv3/extension/_locales/gl/messages.json +++ b/platform/mv3/extension/_locales/gl/messages.json @@ -19,6 +19,10 @@ "message": "Axustes", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Desenvolvemento", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Acerca de", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "modo de filtrado", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Neste sitio web", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Informar dun problema nesta web", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Abrir o panel", "description": "English: Click to open the dashboard" @@ -56,7 +68,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": { @@ -68,7 +80,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupRegions": { - "message": "Rexións, linguaxes", + "message": "Rexións, linguas", "description": "Header for a ruleset section in 'Filter lists pane'" }, "aboutChangelog": { @@ -99,13 +111,73 @@ "message": "Dependencias externas (GPLv3-compatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Benvida", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Información para arranxar problemas", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Para evitar a sobrecarga de traballo para as persoas voluntarias con duplicados dos problemas, comproba que aínda non se informou sobre o problema. Nota: ao premer no botón enviarás a orixe da páxina a GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "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" }, - "firstRunDescription": { - "message": "Acabas de instalar uBO Lite. Aquí podes escoller o modo de filtrado para usar en todas as páxinas web.\n\nPor defecto, o modo Básico está seleccionado porque non require o permiso de lectura ou modificar datos. Se confías en uBO Lite, podes darlle máis permisos para ler e modificar os datos de todos os sitios web para poder realizar por defecto un filtrado máis preciso en todas as páxinas web.", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "Modo de filtrado por defecto", @@ -136,7 +208,7 @@ "description": "This describes the 'basic' filtering mode" }, "optimalFilteringModeDescription": { - "message": "Filtrado avanzado da rede e filtrado extendido específico usando listas de filtrado seleccionadas.\n\nRequire permisos máis amplos para ler e modificar datos en todas as webs.", + "message": "Filtrado avanzado da rede e filtrado estendido específico usando listas de filtrado seleccionadas.\n\nRequire permisos máis amplos para ler e modificar datos en todas as webs.", "description": "This describes the 'optimal' filtering mode" }, "completeFilteringModeDescription": { @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Modo desenvolvemento", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Permitir acceso a funcións pensadas para persoas con experiencia técnica.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Entrar no modo eliminador de elementos", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Sair do modo eliminador de elementos", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Crear un filtro personalizado", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Retirar un filtro personalizado", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Ver:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Detalles do modo de filtrado", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Regras DNR persoais", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Regras DNR de…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Conxunto de regras dinámicas", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Conxunto de regras de sesión", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Gardar", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Reverter", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Importar e engadir…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exportar…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Non engadir contido desde orixes non fiables", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Número de regras rexistradas: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move o desprazador para elixir a mellor concordancia", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Elixir", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Vista previa", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Crear", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Escolle un filtro para destacar os elementos que representa na páxina web. Preme no caldeiro do lixo para eliminar un filtro.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/gu/messages.json b/platform/mv3/extension/_locales/gu/messages.json index 4bbb5e389bf08..ef4d2656fc21e 100644 --- a/platform/mv3/extension/_locales/gu/messages.json +++ b/platform/mv3/extension/_locales/gu/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": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +68,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,13 +111,73 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/he/messages.json b/platform/mv3/extension/_locales/he/messages.json index beb73f27377fd..d1cfa9e977f7a 100644 --- a/platform/mv3/extension/_locales/he/messages.json +++ b/platform/mv3/extension/_locales/he/messages.json @@ -19,6 +19,10 @@ "message": "הגדרות", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "פיתוח", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "על אודות", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "מצב מסנן", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "באתר זה", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "דווח על בעיה באתר זה", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "פתיחת לוח־המחוונים", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "תלויות חיצוניות (תואם GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "ברוך בואך", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "מידע לפתרון בעיות", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "כדי להימנע מהכבדה על מתנדבים בדווחים כפולים, נא לודא שבעיה דומה טרם דווחה.", + "description": "A paragraph in the filter issue reporter section" + }, + "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" }, - "firstRunDescription": { - "message": "התקנת uBO Lite הסתיימה זה עתה. ניתן לבחור כאן את אופן סינון ברירת המחדל בכל אתרי הרשת.\n\nכברירת מחדל, ייבחר אופן סינון בסיסי מאחר והוא אינו דורש הרשאות קריאה ושינוי נתונים. 'סומכים על uBO Lite?' אם כן, ניתן להעניק ל־uBO Lite הרשאות נרחבות לכתיבה ושינוי נתונים בכלול אתרי הרשת על מנת לאפשר יכולות סינון מתקדמות יותר כבררת מחדל.", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "מצב סינון ברירת מחדל", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "מצב מפתחים", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "מאפשר גישה ליכולות עבור משתמשים טכניים.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "יצירת מסנן מותאם אישית", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "מחיקת מסנן מותאם אישית", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "הצג", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "פרטי מצב סינון", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "חוקי DNR אישיים", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "חוקי DNR של...", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "קבוצת חוקים דינמיים", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "קבוצת חוקי מפגש (session)", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "שמירה", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "ביטול שינויים", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "ייבא וצרף…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "ייצוא…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "אל תוסיפו תוכן ממקורות לא מהיימנים", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "מספר החוקים שנרשמו: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "הזיזו את המחוג לבחירת ההתאמה הטובה ביותר", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "בחירה", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "תצוגה מקדימה", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "יצירה", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "בחרו את המסנן למטה להצגת הרכיבים התואמים בדף האינטרנט. לחצו על פח האשפה למחיקת המסנן.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/hi/messages.json b/platform/mv3/extension/_locales/hi/messages.json index 244acb89cb7b6..4a31897926fd4 100644 --- a/platform/mv3/extension/_locales/hi/messages.json +++ b/platform/mv3/extension/_locales/hi/messages.json @@ -19,6 +19,10 @@ "message": "सेटिंग्स", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "विकास", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "जानकारी", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "फ़िल्टरिंग मोड", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "इस वेबसाइट पर किसी समस्या को रिपोर्ट करें", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "डैशबोर्ड खोलें", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "बाहरी निर्भरता (GPLv3-compatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "स्वागत", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "आपने अभी-अभी uBO Lite स्थापित किया है. आप यहां सभी वेबसाइटों पर उपयोग करने के लिए डिफ़ॉल्ट फ़िल्टरिंग मोड चुन सकते हैं.\n\nडिफ़ॉल्ट रूप से, बुनियादी मोड चुना जाता है क्योंकि इसमें डेटा को पढ़ने और बदलने की अनुमति की आवश्यकता नहीं होती है. यदि आप uBO Lite पर भरोसा करते हैं, तो आप डिफ़ॉल्ट रूप से सभी वेबसाइटों के लिए अधिक उन्नत फ़िल्टरिंग क्षमताओं को सक्षम करने के लिए सभी वेबसाइटों पर डेटा को पढ़ने और बदलने की व्यापक अनुमति दे सकते हैं.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "डिफ़ॉल्ट फ़िल्टरिंग मोड", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/hr/messages.json b/platform/mv3/extension/_locales/hr/messages.json index 2ae0291a129f3..1f4d3afbaad11 100644 --- a/platform/mv3/extension/_locales/hr/messages.json +++ b/platform/mv3/extension/_locales/hr/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Bloker sadržaja bez dopuštenja. Blokira oglase, oglasne pratitelje, kripto \"rudare\" i ostalo odmah nakon instalacije.", + "message": "Učinkovit blokator sadržaja. Blokira oglase, oglasne pratitelje, kripto \"rudare\" i ostalo odmah nakon instalacije.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Postavke", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Razvoj", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "O aplikaciji", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "Način filtriranja", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": " Na ovoj web stranici", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Prijavi problem", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Otvori nadzornu ploču", "description": "English: Click to open the dashboard" @@ -56,7 +68,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Zloćudne domene", + "message": "Zaštita od zlonamjernog softvera, sigurnost", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,13 +111,73 @@ "message": "Vanjski korišteni programi (GPLv3-kompatiblini):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Dobrodošli", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Informacije o rješavanju problema", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Kako biste izbjegli opterećivanje volontera duplim prijavama, provjerite nije li problem već prijavljen. Napomena: klik na gumb uzrokovat će slanje izvorne stranice na GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Nađi slične prijave na GitHub-u", + "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" }, - "firstRunDescription": { - "message": "Upravo ste instalirali uBO Lite. Ovdje možete odabrati zadani način filtriranja za korištenje na svim web stranicama.\n\nPrema zadanim postavkama odabran je način rada Osnovni jer ne zahtijeva dopuštenje za čitanje i promjenu podataka. Ako vjerujete uBO Liteu, možete mu dati široko dopuštenje za čitanje i promjenu podataka na svim web stranicama kako biste prema zadanim postavkama omogućili naprednije mogućnosti filtriranja za sva web mjesta.", - "description": "Descriptive text shown at first install time only " + "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 na GitHub-u", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Zadani način filtriranja", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Način rada za programere", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Omogućuje pristup značajkama prikladnim za tehničke korisnike.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Ukloni element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Zatvori način rada uklanjanja elementa", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Napravi prilagođeni filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Ukloni prilagođeni filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Pregled:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Detalji načina filtriranja", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Prilagođena pravila DNR-a", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR pravila …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dinamički skup pravila", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Skup pravila sesije", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Spremi", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Poništi", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Uvesti i dodati...", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Izvoz...", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Ne dodavajte sadržaj iz nepouzdanih izvora", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Broj registriranih pravila: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Pomaknite klizač za odabir najboljeg podudaranja", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Odaberi", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Pregled", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Napravi", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Odaberite filter u nastavku kako biste istaknuli odgovarajuće elemente na web stranici. Kliknite koš za smeće kako biste uklonili filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/hu/messages.json b/platform/mv3/extension/_locales/hu/messages.json index 3ec2b0e2ece25..6443afa83524f 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": { @@ -19,6 +19,10 @@ "message": "Beállítások", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Fejlesztés", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Névjegy", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "szűrési mód", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "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 +111,76 @@ "message": "Külső függőségek (GPLv3-kompatibilis):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Üdvözlünk", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Hibakeresési információk", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Az önkéntesek terhelésének csökkentése érdekében győződjön meg róla, hogy a hiba még nem lett jelentve. Megjegyzés: a gombra kattintás azt okozza, hogy a lap eredete el lesz küldve a GitHub részére.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "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" }, - "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.", - "description": "Descriptive text shown at first install time only " + "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" }, "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 +188,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 +200,7 @@ "description": "Name of blocking mode 2" }, "filteringMode3Name": { - "message": "elkészült", + "message": "teljes", "description": "Name of blocking mode 3" }, "basicFilteringModeDescription": { @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Fejlesztői mód", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Hozzáférést biztosít a képzettebb felhasználóknak való funkciókhoz.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Belépés az elemeltávolító módba", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Kilépés az elemeltávolító módból", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Nézet:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Szűrési mód részletei", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Egyéni DNR szabályok", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR szabályok ehhez…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dinamikus szabálykészlet", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Munkamenet szabálykészlete", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Mentés", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Visszaállítás", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Importálás és hozzáadás…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exportálás…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Ne adjon hozzá megbízhatatlan forrásokból származó tartalmat.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Regisztrált szabályok száma: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/hy/messages.json b/platform/mv3/extension/_locales/hy/messages.json index 6de0ec8a17e86..fa52658197a34 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": { @@ -19,6 +19,10 @@ "message": "Կարգավորումներ", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Ընդլայնման մասին", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "զտման ռեժիմ", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Զեկուցել կայքի հետ խնդրի մասին", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Բացել կառավահանը", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Արտաքին կախվածություններ (GPLv3-համատեղելի)՝", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Բարի գալուստ", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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": "Վեբկայքը՝", + "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" }, - "firstRunDescription": { - "message": "Դուք հենց նոր տեղադրեցիք uBO Lite-ը։ Այստեղ Դուք կարող եք զտման ստանդարտ ռեժիմ ընտրել բոլոր կայքերի համար։\n\nԼռելյայն կերպով ընտրված է հիմնական ռեժիմը, քանի որ այն չի պահանջում տվյալների ընթերցման և փոփոխման թույլտվություն։ Եթե վստահում եք uBO Lite-ին, կարող եք տալ դրան բոլոր կայքերում տվյալների ընթերցման և փոփոխման լայն իրավունքներ՝ բոլոր կայքերի համար զտման ավելի առաջադեմ հնարավորությունները լռելյայն կերպով միացնելու համար։", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Զտման լռելյայն ռեժիմ", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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": "Հետ գնալ", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Փակել այս պատուհանը", + "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": "Շարունակել", + "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/id/messages.json b/platform/mv3/extension/_locales/id/messages.json index 421f091afb516..b4e838b1b05cd 100644 --- a/platform/mv3/extension/_locales/id/messages.json +++ b/platform/mv3/extension/_locales/id/messages.json @@ -19,6 +19,10 @@ "message": "Pengaturan", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Mengembangkan", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Tentang", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "mode filter", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "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,13 +111,73 @@ "message": "Dependensi eksternal (kompatibel GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Selamat datang", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Informasi pemecahan masalah", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Untuk menghindari membebani sukarelawan dengan laporan duplikat, harap verifikasi bahwa masalah tersebut belum dilaporkan.", + "description": "A paragraph in the filter issue reporter section" + }, + "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" }, - "firstRunDescription": { - "message": "Terima kasih telah memasang uBO Lite. Anda bisa memilih di sini mode filter bawaan untuk digunakan pada semua situs web.\n\nSecara bawaan, mode Dasar akan dipilih karena tidak membutuhkan izin untuk membaca dan mengubah data. Jika Anda mempercayai uBO Lite, Anda bisa memberikan izin tambahan untuk membaca dan mengubah data pada semua situs web untuk mengaktifkan kemampuan filter yang lebih luas untuk semua situs web secara bawaan.", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "Mode filter bawaan", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Mode pengembang", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Mengaktifkan akses ke fitur yang sesuai untuk pengguna teknis.", + "description": "Short description for a checkbox in the options page" + }, + "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": "Halaman diblokir karena cocok dengan filter yang ada di dalam {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "Halaman yang diblokir ingin beralih ke situs yang lain. Jika Anda memilih untuk melanjutkan, Anda akan langsung diarahkan ke: {{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" + }, + "zapperTipEnter": { + "message": "Masuk ke mode penghapus elemen", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Keluar dari mode penghapus elemen", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Simpan", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Kembalikan", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Impor dan tambahkan…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Ekspor…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Jumlah aturan yang terdaftar: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/it/messages.json b/platform/mv3/extension/_locales/it/messages.json index beea941700736..fe1910528fa41 100644 --- a/platform/mv3/extension/_locales/it/messages.json +++ b/platform/mv3/extension/_locales/it/messages.json @@ -4,55 +4,67 @@ "description": "extension name." }, "extShortDesc": { - "message": "Un blocco sperimentale che non richiede permessi. Blocca pubblicità, tracker, cryptominer e altro ancora.", + "message": "Un efficiente bloccatore dei contenuti. Blocca annunci, tracker, minatori e altro ancora subito dopo l'installazione.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { - "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": { - "message": "uBO Lite — Pannello di controllo", + "message": "uBO Lite — Cruscotto", "description": "English: uBO Lite — Dashboard" }, "settingsPageName": { - "message": "Opzioni", + "message": "Impostazioni", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Sviluppo", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Informazioni", "description": "appears as tab name in dashboard" }, "aboutPrivacyPolicy": { - "message": "Informativa sulla privacy", + "message": "Politica di riservatezza", "description": "Link to privacy policy on GitHub (English)" }, "popupFilteringModeLabel": { "message": "Modalità di filtraggio", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "In questo sito web", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Segnala un problema con questo sito", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { - "message": "Apri il pannello di controllo", + "message": "Apri il cruscotto", "description": "English: Click to open the dashboard" }, "popupMoreButton": { - "message": "Altro", + "message": "Più", "description": "Label to be used to show popup panel sections" }, "popupLessButton": { - "message": "Nascondi", + "message": "Meno", "description": "Label to be used to hide popup panel sections" }, "3pGroupDefault": { - "message": "Predefiniti", + "message": "Predefinite", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAds": { - "message": "Pubblicità", + "message": "Inserz.", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupPrivacy": { - "message": "Privacy", + "message": "Riservatezza", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { @@ -60,11 +72,11 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { - "message": "Disturbi", + "message": "Scocciature", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMisc": { - "message": "Generici", + "message": "Vari", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupRegions": { @@ -72,7 +84,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "aboutChangelog": { - "message": "Registro delle modifiche", + "message": "Reg. modifiche", "description": "" }, "aboutCode": { @@ -92,27 +104,87 @@ "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):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Ciao", - "description": "The header text for the welcome message section" + "supportS6H": { + "message": "Segnala un problema con un filtro", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "Segnala i problemi di filtraggio con siti web specifici nel tracciatore problemi uBlockOrigin/uAssets. Richiede un account GitHub.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS5H": { + "message": "Informazioni sulla risoluzione dei problemi", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Per evitare di gravare sui volontari con segnalazioni duplicate, verifica che il problema non sia già stato segnalato. Nota: cliccando il pulsante l'origine della pagina sarà inviata a GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Trova segnalazioni simili in GitHub", + "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 inserzioni o loro residui", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Ha sovrapposizioni o altri fastidi", + "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 riservatezza", + "description": "An entry in the widget used to select the type of issue" }, - "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ù.", - "description": "Descriptive text shown at first install time only " + "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 nuova segnalazione in GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "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 in un determinato sito web in base alla modalità che funziona meglio per quel sito. Ogni modalità presenta vantaggi e svantaggi.", "description": "This describes the default filtering mode setting" }, "filteringMode0Name": { @@ -120,7 +192,7 @@ "description": "Name of blocking mode 0" }, "filteringMode1Name": { - "message": "di base", + "message": "basilare", "description": "Name of blocking mode 1" }, "filteringMode2Name": { @@ -132,31 +204,175 @@ "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 nei 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 in 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 in tutti i siti web.\n\nIl filtraggio esteso generico può causare un maggiore uso delle risorse della pagina web.", "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Modalità sviluppatore", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Abilita l'accesso a funzioni adatte a utenti tecnici.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Accedi alla modalità blocco rapido", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Esci dalla modalità blocco rapido", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Crea un filtro personalizzato", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Rimuovi un filtro personalizzato", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Vista:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Dettagli modalità filtraggio", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Regole DNR personali", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Regole DNR per …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Gruppo regole dinamiche", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Gruppo regole di sessione", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Salva", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Ritorna", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Importa e accoda…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Esporta…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Non aggiungere contenuti da fonti non affidabili", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Numero di regole registrate: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Sposta il cursore per selezionare la corrispondenza migliore", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Scegli", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Anteprima", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Crea", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Seleziona un filtro per evidenziare gli elementi corrispondenti nella pagina web. Clicca il cestino per rimuovere un filtro.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/ja/messages.json b/platform/mv3/extension/_locales/ja/messages.json index 28ad8753b9d6f..b281beef13c12 100644 --- a/platform/mv3/extension/_locales/ja/messages.json +++ b/platform/mv3/extension/_locales/ja/messages.json @@ -19,6 +19,10 @@ "message": "設定", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "uBO Lite について", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "フィルタリングモード", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "このサイト上での問題を報告", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "ダッシュボードを開く", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "外部依存関係 (GPLv3 互換):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "ようこそ", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "トラブルシューティング情報", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "重複した報告によってボランティアに負担をかけないように、問題がすでに報告されていないか確認してください。 注意: ボタンをクリックすると、ページのオリジンが GitHub に送信されます。", + "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" }, - "firstRunDescription": { - "message": "uBO Lite のインストールが完了しました。すべてのサイトに適用するデフォルトのフィルタリングモードを選んでください。\n\nデフォルトでは、データの読み書きの権限が必要ない基本モードが選択されています。 uBO Lite を信用してもらえるなら、データの読み書きや変更の権限を許可してもらえればすべてのサイトに対してより詳細なフィルタリングを有効化できます。", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "デフォルトのフィルタリングモード", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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 へ移動します: {{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" + }, + "zapperTipEnter": { + "message": "要素抹消モードを開始", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "要素抹消モードを終了", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/ka/messages.json b/platform/mv3/extension/_locales/ka/messages.json index c728583fa9ef8..324513a308ee8 100644 --- a/platform/mv3/extension/_locales/ka/messages.json +++ b/platform/mv3/extension/_locales/ka/messages.json @@ -19,6 +19,10 @@ "message": "პარამეტრები", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "შემუშავება", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "შესახებ", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "გაფილტვრის რეჟიმი", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "ამ ვებსაიტზე", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "ამ საიტზე ხარვეზის მოხსენება", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "სამართავის გახსნა", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "ცალკეული დაქვემდებარებული პროექტები (GPLv3-თან თავსებადი):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "მოგესალმებით", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "მონაცემები ხარვეზის მოსაგვარებლად", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "მოხალისეები რომ არ მოცდნენ ერთნაირი მოსხენებების გაცნობით, გთხოვთ გადაამოწმოთ, უკვე ხომ არაა გაგზავნილი საჩივარი ამ ხარვეზზე. გაითვალისწინეთ: ღილაკზე დაწკაპების შედეგად გვერდის მონაცემები გაიგზავნება GitHub-ზე.", + "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" }, - "firstRunDescription": { - "message": "თქვენ ახლახან დააყენეთ uBO Lite. აქვე შეგიძლიათ აირჩიოთ ფილტრაციის ნაგულისხმევი რეჟიმი ყველა საიტზე გამოსაყენებლად.\n\nნაგულისხმევად ძირითადი რეჟიმია შერჩეული, ვინაიდან არ საჭიროებს მონაცემთა წაკითხვისა და ცვლილების ნებართვებს. თუ თქვენთვის სანდოა uBO Lite, შეგიძლიათ დართოთ მონაცემთა წაკითხვისა და შეცვლის ნება ყველა საიტზე გაუმჯობესებული ფილტრაციის ნაგულისხმევად გამოყენებისთვის.", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "გაფილტვრის ნაგულისხმევი რეჟიმი", @@ -147,6 +219,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 +232,147 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "შემმუშვებლის რეჟიმი", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "შესაძლებლობები გამოცდილი მომხმარებლებისთვის.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "ნაწილების ამოჭრის რეჟიმში გადასვლა", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "ნაწილების ამოჭრის რეჟიმიდან გასვლა", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "მორგებული ფილტრის შექმნა", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "მორგებული ფილტრის მოცილება", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "ხედი:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "ფილტრის რეჟიმი ვრცლად", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "მორგებული DNR-წესები", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR-წესები…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "ცვალებადი წესების კრებული", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "სეანსის წესების კრებული", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "შენახვა", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "დაბრუნება", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "შეტანა და დამატება…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "გატანა…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "ნუ დაამატებთ შიგთავსს არასანდო წყაროებიდან.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "დამოწმებული წესები სულ: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "გადაადგილეთ სრიალა უკეთ დამთხვევისთვის", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "აღება", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "შეთვალიერება", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "შექმნა", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "აირჩიეთ ქვემოთ ფილტრი შესაბამისი ნაწილების მოსანიშნად ვებგვერდზე. დაწკაპეთ სანაგვე ყუთი ფილტრის მოსაცილებლად.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/kk/messages.json b/platform/mv3/extension/_locales/kk/messages.json index 4bbb5e389bf08..ef4d2656fc21e 100644 --- a/platform/mv3/extension/_locales/kk/messages.json +++ b/platform/mv3/extension/_locales/kk/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": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +68,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,13 +111,73 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/kn/messages.json b/platform/mv3/extension/_locales/kn/messages.json index 30c578f94ffdd..43bb31a888e24 100644 --- a/platform/mv3/extension/_locales/kn/messages.json +++ b/platform/mv3/extension/_locales/kn/messages.json @@ -19,6 +19,10 @@ "message": "ಸಂಯೋಜನೆಗಳು", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "ಬಗ್ಗೆ", "description": "appears as tab name in dashboard" @@ -28,9 +32,17 @@ "description": "Link to privacy policy on GitHub (English)" }, "popupFilteringModeLabel": { - "message": "filtering mode", + "message": "ಫಿಲ್ಟರಿಂಗ್ ಮೋಡ್", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "ಡ್ಯಾಶ್‌ಬೋರ್ಡ್ ತೆರೆಯಿರಿ", "description": "English: Click to open the dashboard" @@ -56,7 +68,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,13 +111,73 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "ಸ್ವಾಗತ", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", @@ -124,7 +196,7 @@ "description": "Name of blocking mode 1" }, "filteringMode2Name": { - "message": "optimal", + "message": "ಸೂಕ್ತ", "description": "Name of blocking mode 2" }, "filteringMode3Name": { @@ -144,11 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/ko/messages.json b/platform/mv3/extension/_locales/ko/messages.json index d066b63af68a8..eca6fabd194c3 100644 --- a/platform/mv3/extension/_locales/ko/messages.json +++ b/platform/mv3/extension/_locales/ko/messages.json @@ -19,6 +19,10 @@ "message": "설정", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "개발자용", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "정보", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "필터링 모드", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "이 사이트의 이슈를 신고하기", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "대시보드 열기", "description": "English: Click to open the dashboard" @@ -92,20 +104,80 @@ "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" }, - "firstRunSectionLabel": { - "message": "환영합니다", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "문제 해결 정보", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "봉사자들이 중복 신고로 인해 부담을 겪지 않도록, 해당 이슈가 이미 신고되지는 않았는지 확인해주시기 바랍니다.", + "description": "A paragraph in the filter issue reporter section" + }, + "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" }, - "firstRunDescription": { - "message": "uBO Lite를 설치하셨습니다. 모든 웹사이트에 적용할 기본 필터링 모드를 선택해주세요.\n\n데이터를 읽고 변경하는 권한이 필요 없는 기본 모드가 기본 설정입니다. uBO Lite를 신뢰하신다면, 모든 웹사이트에서 데이터를 읽고 변경하는 권한을 부여해서 모든 웹사이트에 대해 고급 필터링 기능을 기본적으로 켤 수 있습니다.", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "기본 필터링 모드", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "개발자 모드", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "기술적 사용자를 위한 기능에 접근할 수 있도록 합니다.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "구성 요소 제거 모드로 진입", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "구성 요소 제거 모드 종료", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "보기:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "필터링 모드 상세정보", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "사용자 지정 DNR 규칙", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR 규칙…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "동적 규칙 목록", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "세션 규칙 목록", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "저장", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "되돌리기", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "가져오기 및 추가하기…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "내보내기…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "신뢰할 수 없는 출처의 콘텐츠를 추가하지 마십시오", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "등록된 규칙 수: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/lt/messages.json b/platform/mv3/extension/_locales/lt/messages.json index 3f0bad82bbc7b..12bee815fe534 100644 --- a/platform/mv3/extension/_locales/lt/messages.json +++ b/platform/mv3/extension/_locales/lt/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": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Nustatymai", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Apie", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +68,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,13 +111,73 @@ "message": "Išorinės priklausomybės (suderinamos su „GPLv3“):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", @@ -144,11 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/lv/messages.json b/platform/mv3/extension/_locales/lv/messages.json index a37ba6dda83c1..5005991c3063d 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": { @@ -19,18 +19,30 @@ "message": "Iestatījumi", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Izstrādāt", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Par", "description": "appears as tab name in dashboard" }, "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" }, + "popupLocalToolsLabel": { + "message": "Šajā tīmekļvietnē", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Ziņot par nepilnību šajā tīmekļa vietnē", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Atvērt vadības paneli", "description": "English: Click to open the dashboard" @@ -60,7 +72,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,13 +111,73 @@ "message": "Ārējās atkarības (GPLv3 saderīgas):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Sveicināti!", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Traucējummeklēšanas informācija", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Lai izvairītos no brīvprātīgo noslogošanas ar ziņojumiem, kas atkārtojas, lūgums pārbaudīt, ka par šādu nepilnību jau nav ziņots. Piebilde: klikšķināšana uz pogas izraisīs arī lapas izcelsmes nosūtīšanu uz GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "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" }, - "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.", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "Noklusējuma aizturēšanas veids", @@ -128,7 +200,7 @@ "description": "Name of blocking mode 2" }, "filteringMode3Name": { - "message": "pilnīgais", + "message": "pilnais", "description": "Name of blocking mode 3" }, "basicFilteringModeDescription": { @@ -136,17 +208,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Izstrādātāja režīms", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Iespējot piekļuvi iespējām, kas piemērotas tehniskiem lietotājiem.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Pārslēgties uz elementu iznīcināšanu", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Iziet no elementu iznīcināšanas", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Izveidot pielāgotu aizturētāju", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Noņemt pielāgotu aizturētāju", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Apskatīt", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Aizturēšanas režīma informācija", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Pielāgotas DNR kārtulas", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR kārtulas …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dinamiska kārtulu kopa", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Sesijas kārtulu kopa", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Saglabāt", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Atjaunot", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Ievietot un pievienot…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Izgūt…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Nevajag pievienot saturu no neuzticamiem avotiem.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Reģistrēto kārtulu skaits: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Jābīda slīdnis, lai atlasītu vislabāko atbilstību", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Izvēlēties", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Priekšskatīt", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Izveidot", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Zemāk jāatlasa atlasītājs, lai tīmekļa lapā izceltu atbilstošos elementus. Klikšķināt uz atkritnes, lai noņemtu aizturētāju.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/mk/messages.json b/platform/mv3/extension/_locales/mk/messages.json index cb7631b2bbf95..8f35d01b8c4df 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": { @@ -19,6 +19,10 @@ "message": "Прилагодби", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Информации за...", "description": "appears as tab name in dashboard" @@ -31,8 +35,16 @@ "message": "Начини на прочистување", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Пријави проблем на оваа веб-страница", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { - "message": "Отварање на Контролна Табла", + "message": "Отварање на Контролна плоча", "description": "English: Click to open the dashboard" }, "popupMoreButton": { @@ -40,7 +52,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 +68,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 +84,295 @@ "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" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "За да се избегне оптоварување на волонтерите со дупликат пријави, ве молиме проверете дали проблемот веќе не е пријавен.", + "description": "A paragraph in the filter issue reporter section" + }, + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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" }, "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/ml/messages.json b/platform/mv3/extension/_locales/ml/messages.json index 2bffd1a1ffc61..81dfd8ca69102 100644 --- a/platform/mv3/extension/_locales/ml/messages.json +++ b/platform/mv3/extension/_locales/ml/messages.json @@ -19,6 +19,10 @@ "message": "ക്രമീകരണങ്ങൾ", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "കുറിച്ച്", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "ഫിൽട്ടറിംഗ് മോഡ്", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "ഡാഷ്ബോർഡ് തുറക്കുക", "description": "English: Click to open the dashboard" @@ -56,7 +68,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,13 +111,73 @@ "message": "ബാഹ്യ ഡിപൻഡൻസികൾ (ജിപിൽവി3-അനുയോജ്യമായത്):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "സ്വാഗതം", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "നിങ്ങൾ ഇപ്പോൾ uBO Lite ഇൻസ്റ്റാൾ ചെയ്തു. എല്ലാ വെബ്‌സൈറ്റുകളിലും ഉപയോഗിക്കുന്നതിന് ഇവിടെ നിങ്ങൾക്ക് ഡിഫോൾട്ട് ഫിൽട്ടറിംഗ് മോഡ് തിരഞ്ഞെടുക്കാം.\n\nസ്ഥിരസ്ഥിതിയായി, അടിസ്ഥാന മോഡ് തിരഞ്ഞെടുത്തു, കാരണം ഡാറ്റ വായിക്കാനും പരിഷ്ക്കരിക്കാനും അനുമതി ആവശ്യമില്ല. നിങ്ങൾ uBO Lite-നെ വിശ്വസിക്കുന്നുവെങ്കിൽ, ഡിഫോൾട്ടായി എല്ലാ വെബ്‌സൈറ്റുകൾക്കും കൂടുതൽ വിപുലമായ ഫിൽട്ടറിംഗ് കഴിവുകൾ പ്രാപ്‌തമാക്കുന്നതിന് എല്ലാ വെബ്‌സൈറ്റുകളിലെയും ഡാറ്റ വായിക്കാനും പരിഷ്‌ക്കരിക്കാനും നിങ്ങൾക്ക് വിശാലമായ അനുമതി നൽകാം.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "ഡിഫോൾട്ട് ഫിൽട്ടറിംഗ് മോഡ്", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/mr/messages.json b/platform/mv3/extension/_locales/mr/messages.json index 4bbb5e389bf08..ef4d2656fc21e 100644 --- a/platform/mv3/extension/_locales/mr/messages.json +++ b/platform/mv3/extension/_locales/mr/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": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +68,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,13 +111,73 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/ms/messages.json b/platform/mv3/extension/_locales/ms/messages.json index 817a81f39af9d..dd15e7882c841 100644 --- a/platform/mv3/extension/_locales/ms/messages.json +++ b/platform/mv3/extension/_locales/ms/messages.json @@ -19,6 +19,10 @@ "message": "Tetapan", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Mengenai", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "mod penapisan", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Buka papan pemuka", "description": "English: Click to open the dashboard" @@ -56,7 +68,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,13 +111,73 @@ "message": "Pergantungan luaran (serasi dengan GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Selamat datang", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "Anda baru sahaja memasang uBO Lite. Di sini anda boleh memilih mod penapisan lalai untuk digunakan pada semua tapak web.\n\nSecara lalai, mod Asas dipilih kerana ia tidak memerlukan kebenaran untuk membaca dan mengubah suai data. Jika anda mempercayai uBO Lite, anda boleh memberikannya kebenaran untuk membaca dan mengubah suai data pada semua tapak web untuk mendayakan keupayaan penapisan yang lebih maju untuk semua tapak web secara lalai.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Mod penapisan lalai", @@ -147,6 +219,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 +232,147 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/nb/messages.json b/platform/mv3/extension/_locales/nb/messages.json index ed850b77db4ad..e8afc24d87bc6 100644 --- a/platform/mv3/extension/_locales/nb/messages.json +++ b/platform/mv3/extension/_locales/nb/messages.json @@ -19,6 +19,10 @@ "message": "Innstillinger", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Om", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtreringsmodus", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Rapporter et problem på dette nettstedet", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Åpne dashbordet", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Eksterne avhengigheter (GPLv3-kompatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Velkommen", - "description": "The header text for the welcome message section" + "supportS6H": { + "message": "Rapporter om filterproblem", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "Rapporter filterproblemer med bestemte nettsteder til uBlockOrigin/uAssets problemsporing. Krever en GitHub-konto.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS5H": { + "message": "Feilsøkingsinformasjon", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "For å unngå å belaste de frivillige med dobbeltrapporter, må du kontrollere at problemet ikke allerede har blitt rapportert. Noter: ved å klikke på knappen vil sidens opprinnelse bli sendt til GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Finn lignende rapporter på GitHub", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Nettsidens adresse:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Nettsiden...", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Velg en oppføring --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Viser reklame eller reklamerester", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Har overlegg eller andre plager", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Oppdager uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Har personvernrelaterte problemer", + "description": "An entry in the widget used to select the type of issue" }, - "firstRunDescription": { - "message": "Du har nettopp installert uBO Lite. Her kan du velge standard-filtreringsmodusen som skal brukes på alle nettsteder.\n\nSom standard er modusen Grunnleggende valgt fordi den ikke krever tillatelse til å lese og endre data. Hvis du stoler på uBO Lite, kan du gi uBO Lite bred tillatelse til å lese og endre data på alle nettsteder for å aktivere mer avanserte filtreringsfunksjoner for alle nettsteder som standard.", - "description": "Descriptive text shown at first install time only " + "supportS6Select1Option5": { + "message": "Fungerer ikke når uBO Lite er aktivert", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Åpner uønskede faner eller vinduer", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Fører til skadelig programvare og/eller phishing", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Merk nettsiden som «NSFW» (“Not Safe For Work”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Opprett ny rapport på GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Standard filtreringsmodus", @@ -144,9 +216,13 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Liste over vertsnavn der ingen filtrering vil finne sted", + "message": "Liste over nettsider der ingen filtrering vil finne sted.", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[kun vertsnavn]\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 +234,145 @@ "showBlockedCountLabel": { "message": "Vis antall blokkerte forespørsler på verktøylinjeikonet", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLabel": { + "message": "Aktiver streng blokkering", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Navigering til potensielt uønskede nettsteder blir blokkert, og du får tilbud om å fortsette.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Utviklermodus", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Aktiver tilgang til funksjoner som er egnet for tekniske brukere.", + "description": "Short description for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Finn lister", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Side blokkert", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite har forhindret innlasting av følgende side:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Siden ble blokkert på grunn av et matchende filter i {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "Den blokkerte siden ønsker å omdirigere til et annet nettsted. Hvis du velger å fortsette, vil du navigere direkte til: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "uten parametere", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Gå tilbake", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Lukk dette vinduet", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Ikke varsle igjen om dette nettstedet", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Fortsett", + "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Gå til element­fjernings­modus", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Forlat elementfjerningsmodus", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Lagre", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Tilbakestill", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Importer og legg til...", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Eksporter...", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/nl/messages.json b/platform/mv3/extension/_locales/nl/messages.json index d73b801d6118f..33d5b75bddd2c 100644 --- a/platform/mv3/extension/_locales/nl/messages.json +++ b/platform/mv3/extension/_locales/nl/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Een toestemmingsloze inhoudsblokkeerder. Blokkeert direct na installatie advertenties, trackers, miners en meer.", + "message": "Een efficiënte inhoudsblokkeerder. Blokkeert direct na installatie advertenties, trackers, miners en meer.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Instellingen", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Ontwikkelen", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Over", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtermodus", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Op deze website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Een probleem melden", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Dashboard openen", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Externe afhankelijkheden (GPLv3-compatibel):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Welkom", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Probleemoplossingsinformatie", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Controleer of het probleem niet eerder is gemeld om te voorkomen dat vrijwilligers met dubbele meldingen worden belast. Noot: op de knop klikken zorgt ervoor dat de oorsprong van de pagina naar GitHub wordt verzonden.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Soortgelijke meldingen op GitHub 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" }, - "firstRunDescription": { - "message": "U hebt zojuist uBO Lite geïnstalleerd. Hier kunt u de standaard filtermodus voor het gebruik op alle websites kiezen.\n\nStandaard wordt de modus Basis geselecteerd, omdat hiervoor geen toestemming voor het lezen en aanpassen van gegevens is vereist. Als u uBO Lite vertrouwt, kunt u het brede toestemming voor het lezen en aanpassen van gegevens op alle websites verlenen, zodat standaard meer geavanceerde filtermogelijkheden voor alle websites beschikbaar zijn.", - "description": "Descriptive text shown at first install time only " + "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 op GitHub maken", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Standaard filtermodus", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Ontwikkelaarsmodus", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Schakelt toegang tot voor technische gebruikers geschikte functies in.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Een element­ verwijderen", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Element­wisser­modus sluiten", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Een aangepast filter maken", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Een aangepast filter verwijderen", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Weergeven:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Details van filtermodus", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Aangepaste DNR-regels", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR-regels van …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamische regelset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Sessieregelset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Opslaan", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Ongedaan maken", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Importeren en toevoegen…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exporteren…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Voeg geen inhoud van niet-vertrouwde bronnen toe.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Aantal geregistreerde regels: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Verplaats de schuifregelaar voor de beste overeenkomst", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Kiezen", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Voorbeeld", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Aanmaken", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Selecteer hieronder een filter om overeenkomende elementen in de webpagina te markeren. Klik op de prullenbak om een filter te verwijderen.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/oc/messages.json b/platform/mv3/extension/_locales/oc/messages.json index 4bbb5e389bf08..ef4d2656fc21e 100644 --- a/platform/mv3/extension/_locales/oc/messages.json +++ b/platform/mv3/extension/_locales/oc/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": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +68,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,13 +111,73 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/pa/messages.json b/platform/mv3/extension/_locales/pa/messages.json index 868cc48068375..6a1ed0b05f40a 100644 --- a/platform/mv3/extension/_locales/pa/messages.json +++ b/platform/mv3/extension/_locales/pa/messages.json @@ -19,6 +19,10 @@ "message": "ਸੈਟਿੰਗਾਂ", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "ਇਸ ਬਾਰੇ", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "ਫਿਲਟਰ ਕਰਨ ਦਾ ਮੋਡ", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "ਇਸ ਵੈੱਬਸਾਈਟ ਉੱਤੇ ਮਸਲੇ ਬਾਰੇ ਰਿਪੋਰਟ ਕਰੋ", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "ਡੈਸ਼ਬੋਰਡ ਨੂੰ ਖੋਲ੍ਹੋ", "description": "English: Click to open the dashboard" @@ -56,7 +68,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,13 +111,73 @@ "message": "ਬਾਹਰੀ ਨਿਰਭਰਤਾਵਾਂ (GPLv3-ਅਨੁਕੂਲ):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "ਜੀ ਆਇਆਂ ਨੂੰ", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "ਰਲਦੀਆਂ ਰਿਪੋਰਟਾਂ ਲੱਭੋ", + "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" }, - "firstRunDescription": { - "message": "ਤੁਸੀਂ ਹੁਣੇ ਹੀ uBO Lite ਨੂੰ ਇੰਸਟਾਲ ਕੀਤਾ ਹੈ। ਤੁਸੀਂ ਸਾਰੀਆਂ ਵੈੱਬਸਾਈਟਾਂ ਲਈ ਵਰਤਣ ਵਾਸਤੇ ਮੂਲ ਫਿਲਟਰ ਕਰਨ ਦੇ ਢੰਗ ਨੂੰ ਚੁਣ ਸਕਦੇ ਹੋ।\n\nਮੂਲ ਰੂਪ ਵਿੱਚ ਮੁੱਢਲਾ (Basic) ਢੰਗ ਚੁਣਿਆ ਜਾਂਦਾ ਹੈ, ਕਿਉਂਕਿ ਇਸ ਵਾਸਤੇ ਡਾਟਾ ਪੜ੍ਹਨ ਅਤੇ ਸੋਧਣ ਲਈ ਕਿਸੇ ਵੀ ਮਨਜ਼ੂਰੀ ਦੀ ਲੋੜ ਨਹੀਂ ਹੁੰਦੀ ਹੈ। ਜੇ ਤੁਹਾਨੂੰ uBO Lite ਉੱਤੇ ਭਰੋਸਾ ਹੋਵੇ ਤਾਂ ਤੁਸੀਂ ਇਸ ਨੂੰ ਸਾਰੀਆਂ ਵੈੱਬਸਾਈਟਾਂ ਉੱਤੇ ਮੂਲ ਰੂਪ ਵਿੱਚ ਹੀ ਵੱਧ ਤਕਨੀਕੀ ਫਿਲਟਰ ਸਮਰੱਥਾ ਨੂੰ ਚਾਲੂ ਕਰਨ ਲਈ ਸਭ ਵੈੱਬਸਾਈਟਾਂ ਉੱਤੇ ਡਾਟਾ ਪੜ੍ਹਨ ਅਤੇ ਸੋਧਣ ਲਈ ਜਿਆਦਾ ਮਨਜ਼ੂਰੀ ਦੇ ਸਕਦੇ ਹੋ।", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "ਮੂਲ ਫਿਲਟਰ ਕਰਨ ਦਾ ਢੰਗ", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/pl/messages.json b/platform/mv3/extension/_locales/pl/messages.json index 1c7b89f236beb..cdefbd986be8c 100644 --- a/platform/mv3/extension/_locales/pl/messages.json +++ b/platform/mv3/extension/_locales/pl/messages.json @@ -19,6 +19,10 @@ "message": "Ustawienia", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Programowanie", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "O rozszerzeniu", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "Tryb filtrowania", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Na tej stronie internetowej", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Zgłoś problem z tą stroną", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Otwórz panel sterowania", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Zewnętrzne zależności (kompatybilne z GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Witaj", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Informacje pomocne w rozwiązywaniu problemów", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Sprawdź, czy problem nie został już zgłoszony, aby uniknąć obciążania wolontariuszy duplikatami raportów. Uwaga: kliknięcie przycisku spowoduje wysłanie źródła strony do serwisu GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "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" }, - "firstRunDescription": { - "message": "Właśnie został zainstalowany uBO Lite. Tutaj możesz wybrać domyślny tryb filtrowania, który będzie używany na wszystkich witrynach internetowych.\n\nDomyślnie wybrany jest tryb Podstawowy, ponieważ nie wymaga uprawnień do odczytu i zmiany danych. Jeśli ufasz uBO Lite, możesz nadać mu szerokie uprawnienia do odczytu i zmiany danych na wszystkich witrynach internetowych w celu domyślnego włączenia bardziej zaawansowanych funkcji filtrowania wszystkich witryn internetowych.", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "Domyślny tryb filtrowania", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Tryb programisty", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Włącz dostęp do odpowiednich funkcji dla użytkowników technicznych.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Przejdź do trybu usuwania elementów", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Wyjdź z trybu usuwania elementów", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Utwórz własny filtr", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Usuń własny filtr", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Widok:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Szczegóły trybu filtrowania", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Własne reguły DNR", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Reguły DNR …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamiczny zestaw reguł", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Sesyjny zestaw reguł", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Zapisz", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Przywróć", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Importuj i dołącz…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Eksportuj…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Nie dodawaj zawartości z niezaufanych źródeł", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Liczba zarejestrowanych reguł: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Przesuń suwak, aby wybrać najlepsze dopasowanie", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Wybierz", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Podgląd", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Utwórz", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Wybierz filtr poniżej, aby wyróżnić pasujące elementy na stronie internetowej. Kliknij kosz, aby usunąć filtr.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/pt_BR/messages.json b/platform/mv3/extension/_locales/pt_BR/messages.json index e6265efab5275..94dad68c853c3 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 eficiente de conteúdo. Bloqueia anúncios, rastreadores e muito mais, imediatamente após a instalação.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Configurações", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Desenvolver", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Sobre", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "modo de filtragem", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Neste site", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Relatar um problema", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Abrir painel", "description": "English: Click to open the dashboard" @@ -84,7 +96,7 @@ "description": "English: Contributors" }, "aboutSourceCode": { - "message": "Código fonte", + "message": "Código-fonte", "description": "Link text to source code repo" }, "aboutTranslations": { @@ -99,13 +111,73 @@ "message": "Dependências externas (compatíveis com GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Bem-vindo", - "description": "The header text for the welcome message section" + "supportS6H": { + "message": "Relatar um problema com o filtro", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "Relate problemas dos filtros em sites específicos no rastreador de problemas douBlockOrigin/uAssets. Uma conta do GitHub é necessária.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS5H": { + "message": "Informações para solução de problemas", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Para evitar sobrecarregar os voluntários com relatórios duplicados por favor verifique se o problema já não foi relatado. Observação: clicar no botão fará com que a origem da página seja enviada ao GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Achar relatórios similares no GitHub", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Endereço da página:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "A página…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "— Selecione um tipo —", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Mostra os anúncios ou restos de anúncios", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Tem sobreposições ou outras perturbações", + "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 à privacidade", + "description": "An entry in the widget used to select the type of issue" }, - "firstRunDescription": { - "message": "Você instalou o uBO Lite. Aqui você pode escolher o modo de filtragem padrão pra usar em todos os sites da web.\n\nPor padrão o modo Básico está selecionado porque não requer permissão pra ler e modificar os dados. Se você confia no uBO Lite você pode dar ampla permissão pra ler e modificar os dados em todos os sites da web de modo a ativar as capacidades de filtragem mais avançadas pra todos os sites da web por padrão.", - "description": "Descriptive text shown at first install time only " + "supportS6Select1Option5": { + "message": "Não funciona direito quando o uBO Lite está ativado", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "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 como “NSFW” (“Not Safe For Work”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Criar um novo relatório no GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Modo de filtragem padrão", @@ -147,16 +219,160 @@ "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" }, "autoReloadLabel": { - "message": "Recarregar a página automaticamente quando mudar o modo de filtragem", + "message": "Recarregar a página automaticamente ao alterar o modo de filtragem", "description": "Label for a checkbox in the options page" }, "showBlockedCountLabel": { "message": "Mostrar o número de solicitaçõ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 para sites potencialmente indesejáveis ​​será bloqueada e você terá a opção de prosseguir.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Modo de desenvolvedor", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Ativa o acesso à funcionalidade destinada a usuários técnicos.", + "description": "Short description for a checkbox in the options page" + }, + "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 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 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" + }, + "zapperTipEnter": { + "message": "Remover um elemento", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Sair do modo de remoção de elementos", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Criar um filtro personalizado", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remover um filtro personalizado", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Visualizar:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Detalhes do modo de filtragem", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Regras DNR personalizadas", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Regras DNR de…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Conjunto de regras dinâmicas", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Conjunto de regras da sessão", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Salvar", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Reverter", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Importar e anexar…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exportar…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Não adicione conteúdo de fontes não confiáveis.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Número de regras registradas: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Mova o controle para selecionar a melhor correspondência", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Selecionar", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Pré-visualizar", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Criar", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Selecione um filtro abaixo para destacar os elementos correspondentes na página. Clique na lixeira para remover um filtro.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/pt_PT/messages.json b/platform/mv3/extension/_locales/pt_PT/messages.json index 511db27ff621a..1d697d6220369 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 eficiente. Bloqueia anúncios, rastreadores, mineradores e muito mais imediatamente após a instalação.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Definições", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Programação", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Acerca", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "modo de filtragem", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "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,13 +111,73 @@ "message": "Dependências externas (compatíveis com GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Bem-vindo(a)", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Informação sobre resolução de problemas", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Para evitar sobrecarregar os voluntários com relatórios duplicados, verifique se o problema ainda não foi relatado. Nota: clicar no botão fará com que a origem da página seja enviada para o GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Encontrar relatórios semelhantes no GitHub", + "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" }, - "firstRunDescription": { - "message": "Acabou de instalar o uBO Lite. Pode escolher aqui o modo de filtragem predefinido para usar em todos os websites.\n\nPor predefinição, o modo Básico é selecionado porque não requer a permissão para ler e modificar dados. Se confiar no uBO Lite, pode dar-lhe ampla permissão para ler e modificar dados em todos os websites, a fim de ativar capacidades de filtragem mais avançadas para todos os websites por predefinição.", - "description": "Descriptive text shown at first install time only " + "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": "Classificar a página web como “NSFW” (“Não segura para o trabalho”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Criar novo relatório no GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Modo de filtragem predefinido", @@ -144,19 +216,163 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Modo de programador", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Permite acesso a funcionalidades adequadas a utilizadores técnicos", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Entrar no modo de remoção rápida de elemento", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Sair do modo de remoção rápida de elemento", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Guardar", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Reverter", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Importar e anexar…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exportar…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Número de regras registadas: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/ro/messages.json b/platform/mv3/extension/_locales/ro/messages.json index 70f9bf60ed171..5ffd5a6e1b786 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": { @@ -19,6 +19,10 @@ "message": "Opțiuni", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Despre", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "Mod de filtrare", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Raportează o eroare pe acest site web", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Deschide panoul de control", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Dependențe externe (compatibile GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Bun venit", - "description": "The header text for the welcome message section" + "supportS6H": { + "message": "Raportează o problemă cu filtrele", + "description": "Header of 'Report a filter issue' section in Support pane" + }, + "supportS3P1": { + "message": "Raportează aici o eroare cu filtrele pentru un site specific uBlockOrigin/uAssets issue tracker. Este necesar un cont GitHub.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Pentru a evita încărcarea voluntarilor cu rapoarte duplicate, vă rugăm să verificați dacă problema nu a fost deja raportată.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Găsiți rapoarte similare", + "description": "A clickable link in the filter issue reporter section" + }, + "supportS6URL": { + "message": "Adresa paginii web:", + "description": "Label for the URL of the page" + }, + "supportS6Select1": { + "message": "Pagina web…", + "description": "Label for widget to select type of issue" + }, + "supportS6Select1Option0": { + "message": "-- Alege o intrare --", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option1": { + "message": "Arată reclame sau resturi de reclame", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option2": { + "message": "Are suprapuneri sau alte inconveniente", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option3": { + "message": "Detectează uBO Lite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option4": { + "message": "Are probleme privind confidențialitatea", + "description": "An entry in the widget used to select the type of issue" }, - "firstRunDescription": { - "message": "Tocmai ați instalat uBO Lite. Aici puteți alege modul de filtrare implicit pe toate site-urile.\n\nImplicit, modul de bază este selectat întrucât nu necesită permisiuni pentru a citi și modifica date. Dacă aveți încredere în uBO Lite, puteți să-i acordați permisiuni sporite pentru a citi și modifica datele tututor sitte-rilor pentru a activa capabilități mai avansate de filtrare.", - "description": "Descriptive text shown at first install time only " + "supportS6Select1Option5": { + "message": "Defecțiuni atunci când uBO Lite este activat", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option6": { + "message": "Deschide file sau ferestre nedorite", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "Duce la programe dăunătoare, phishing", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Checkbox1": { + "message": "Etichetați pagina web ca “NSFW” (“Nu este sigur la locul de muncă”)", + "description": "A checkbox to use for NSFW sites" + }, + "supportReportSpecificButton": { + "message": "Creează o nouă sesizare", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Mod de filtrare implicit", @@ -144,9 +216,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": "[doar hostnames]\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 +232,147 @@ "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": "Activați blocarea strictă", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Navigarea către site-uri potențial nedorite va fi blocată și vi se va oferi opțiunea de a continua.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Căutați liste", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Pagină blocată", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite a împiedicat încărcarea următoarei pagini:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Pagina a fost blocată din cauza unui filtru din {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "message": "Pagina blocată dorește să redirecționeze către un alt site. Dacă alegeți să continuați, veți naviga direct către: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "strictblockNoParamsPrompt": { + "message": "fără parametri", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Înapoi", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Închide fereastra", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Nu mă avertiza din nou despre acest site", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Continuă", + "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/ru/messages.json b/platform/mv3/extension/_locales/ru/messages.json index f13511e62cf28..944b748347ee8 100644 --- a/platform/mv3/extension/_locales/ru/messages.json +++ b/platform/mv3/extension/_locales/ru/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": { @@ -19,6 +19,10 @@ "message": "Настройки", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Разработка", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "О расширении", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "режим фильтрации", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "На этом сайте", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Сообщить о проблеме", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Открыть панель управления", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Внешние зависимости (совместимые с GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Добро пожаловать", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Диагностическая информация", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Чтобы не обременять добровольцев повторяющимися отчётами, пожалуйста, убедитесь, что об этой проблеме ещё не сообщали. Примечание: щелчок по кнопке приведёт к отправке адреса посещенной страницы GitHub'у.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Найти похожие отчёты в GitHub", + "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" }, - "firstRunDescription": { - "message": "Вы только что установили uBO Lite. Здесь вы можете выбрать стандартный режим фильтрации для всех веб-сайтов.\n\nПо умолчанию выбран режим Базовый, так как он не требует разрешения на чтение и изменение данных. Если вы доверяете uBO Lite, вы можете дать ему широкие права на чтение и изменение данных на всех веб-сайтах, чтобы включить более продвинутые возможности фильтрации для всех веб-сайтов по умолчанию.", - "description": "Descriptive text shown at first install time only " + "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": "Создать новый отчёт в GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Режим фильтрации по умолчанию", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Режим разработчика", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Включает доступ к функциям, предназначенным для технических пользователей.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Убрать элемент", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Покинуть режим временного скрытия элемента", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Создать свой фильтр", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Удалить свой фильтр", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Просмотр:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Подробности режима фильтрации", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Пользовательские правила DNR", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Правила DNR для…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Динамический набор правил", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Набор правил для сессии", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Сохранить", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Вернуть", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Импортировать и добавить…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Экспортировать…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Не добавлять содержимое из ненадёжных источников", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Число зарегистрированных правил: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Перемещайте ползунок для выбора лучшего варианта", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Выбрать элемент", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Предпросмотр", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Создать", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Выберите фильтр ниже, чтобы подсветить соответствующие элементы на странице. Нажмите на корзину для удаления фильтра.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/si/messages.json b/platform/mv3/extension/_locales/si/messages.json index 4bbb5e389bf08..87d1b9700b8be 100644 --- a/platform/mv3/extension/_locales/si/messages.json +++ b/platform/mv3/extension/_locales/si/messages.json @@ -4,159 +4,375 @@ "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" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { - "message": "About", + "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" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "මෙම අඩවියේ ගැටලුවක් වාර්තා කරන්න", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "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" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "දෝශ නිරාකරණ තොරතුරු", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "අනුපිටපත් වාර්තා සමඟ ස්වේච්ඡා සේවකයින්ට බරක් වීම වළක්වා ගැනීම සඳහා, කරුණාකර ගැටළුව දැනටමත් වාර්තා කර නොමැති බව තහවුරු කරගන්න. සටහන: බොත්තම ක්ලික් කිරීමෙන් පිටුවේ මූලාරම්භය GitHub වෙත යවනු ලැබේ.", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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" }, "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": "දැඩි අවහිර කිරීම සක්‍රීය කරන්න", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "අනවශ්‍ය විය හැකි අඩවි වෙත සංචාලනය අවහිර කරනු ලබන අතර, ඉදිරියට යාමට ඔබට විකල්පය ලබා දෙනු ඇත.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "මූලද්‍රව්‍ය zapper ප්‍රකාරයට ඇතුළු වන්න", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "මූලද්‍රව්‍ය zapper ප්‍රකාරයෙන් ඉවත් වන්න", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/sk/messages.json b/platform/mv3/extension/_locales/sk/messages.json index 91ebfc926a1c6..8b345ebb53982 100644 --- a/platform/mv3/extension/_locales/sk/messages.json +++ b/platform/mv3/extension/_locales/sk/messages.json @@ -19,6 +19,10 @@ "message": "Nastavenia", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Vývoj", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "O doplnku", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "Režim filtrovania", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Na tejto webovej stránke", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Nahlásiť problém na tejto webovej stránke", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Otvoriť ovládací panel", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Externé závislosti (kompatibilné s GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Vitajte", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Informácie o riešení problémov", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Aby ste dobrovoľníkov nezaťažovali duplicitnými hláseniami, overte si, či už problém nebol nahlásený. Poznámka: kliknutím na tlačidlo sa odošle pôvodná stránka na GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Vyhľadať podobné hlásenia", + "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" }, - "firstRunDescription": { - "message": "Práve ste nainštalovali uBO Lite. Tu si môžete vybrať predvolený režim filtrovania, ktorý sa má používať na všetkých webových stránkach.\n\nV predvolenom nastavení je zvolený režim Základný, pretože nevyžaduje povolenie na čítanie a zmenu údajov. Ak dôverujete rozšíreniu uBO Lite, môžete mu udeliť všeobecné oprávnenie na čítanie a zmenu údajov na všetkých webových stránkach, aby ste v predvolenom nastavení umožnili pokročilejšie možnosti filtrovania všetkých webových stránok.", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "Predvolený režim filtrovania", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Vývojársky režim", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Povoliť prístup k funkciám vhodným pre technických používateľov.", + "description": "Short description 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" + }, + "zapperTipEnter": { + "message": "Prejsť do režimu dočasného skrytia prvkov", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Ukončiť režim dočasného skrytia prvkov", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Vytvoriť vlastný filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Odstrániť vlastný filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Zobraziť:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Podrobnosti režimu filtrovania", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Vlastné pravidlá DNR", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Pravidlá DNR…", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamický súbor pravidiel", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Súbor pravidiel relácie", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Uložiť", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Vrátiť späť", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Importovať a pripojiť…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exportovať…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Nepridávajte obsah z nedôveryhodných zdrojov", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Počet zaregistrovaných pravidiel: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Posunutím jazdca vyberte najlepšiu zhodu", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Vybrať", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Náhľad", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Vytvoriť", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Vyberte filter na zvýraznenie zodpovedajúcich prvkov na webovej stránke. Ak chcete filter odstrániť, kliknite na kôš.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/sl/messages.json b/platform/mv3/extension/_locales/sl/messages.json index 4bbb5e389bf08..ef4d2656fc21e 100644 --- a/platform/mv3/extension/_locales/sl/messages.json +++ b/platform/mv3/extension/_locales/sl/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": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +68,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,13 +111,73 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/so/messages.json b/platform/mv3/extension/_locales/so/messages.json index 4bbb5e389bf08..ef4d2656fc21e 100644 --- a/platform/mv3/extension/_locales/so/messages.json +++ b/platform/mv3/extension/_locales/so/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": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +68,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,13 +111,73 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/sq/messages.json b/platform/mv3/extension/_locales/sq/messages.json index 7b8c0748da091..1774626cca892 100644 --- a/platform/mv3/extension/_locales/sq/messages.json +++ b/platform/mv3/extension/_locales/sq/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Një bllokues që bllokon në mënyrë të pavarur reklamat, gjurmuesit, kriptominatorët etj. menjëherë pas instalimit.", + "message": "Një bllokues efikas për reklamat, gjurmuesit, kriptominatorët e të tjera, që vepron menjëherë pas instalimit.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Parametrat", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Zhvilloni", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Info", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "mënyra e filtrimit", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Në këtë faqe interneti", + "description": "Label in the popup panel for the local tools section" + }, + "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,13 +111,73 @@ "message": "Programet kushtëzuese (sipas GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Përshëndetje", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Diagnostikimi i problemeve", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Verifikoni a është raportuar edhe më parë që të mos i lodhni vullnetarët e tjerë me të njëjtat probleme. Shënim: kur klikoni butonin, origjina e faqes do të dërgohet në GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Gjej raporte të ngjashme në GitHub", + "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" }, - "firstRunDescription": { - "message": "Sapo instaluat uBO Lite. Këtu mund të zgjidhni mënyrën e filtrimit që duhet përdorur për të gjitha uebsajtet.\n\nE thjeshta është mënyra standarde, sepse nuk ju merret leje për leximin dhe modifikimin e të dhënave. Nëse keni besim te uBO Lite, mund t'i jepni leje shtesë për leximin dhe modifikimin e të dhënave në të gjitha uebsajtet, në mënyrë që të kryeni një filtrim më të avancuar.", - "description": "Descriptive text shown at first install time only " + "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 në GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Mënyra standarde e filtrimit", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Modaliteti i zhvilluesit", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Mundëson qasjen në funksione të përshtatshme për përdoruesit teknikë.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Aktivizoj asgjësuesin e elementeve", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Mbyll asgjësuesin e elementeve", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Krijo filtër të personalizuar", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Hiq një filtër të personalizuar", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Pamja:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Detalet e mënyrës së filtërimit", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Rregullat DNR të personalizuara", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Rregullat DNR të ...", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Rregullat dinamike", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Rregullat e sesionit", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Ruaj", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Rikthej", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Importoj dhe shtoj…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Eksportoj…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Mos shtoni filtra nga burime të pabesueshme.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Numri i rregullave të regjistruara: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Lëvizni rrëshqitësin për të zgjedhur përputhjen më të mirë", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Përzgjedh", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Parapamje", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Krijoj", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Zgjidh një filtër më poshtë për të nxjerrë në pah elementët që përputhen në faqen e internetit. Klikoni te koshi për të hequr një filtër.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/sr/messages.json b/platform/mv3/extension/_locales/sr/messages.json index 5680a04dc5823..4453ffafe14de 100644 --- a/platform/mv3/extension/_locales/sr/messages.json +++ b/platform/mv3/extension/_locales/sr/messages.json @@ -19,6 +19,10 @@ "message": "Подешавања", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "О апликацији", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "режим филтрирања", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Пријавите проблем на овом веб сајту", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Отвори контролну таблу", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Спољне зависности (компатибилно са GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Добродошли", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Да не бисте оптерећивали волонтере дуплим извештајима, проверите да ли је проблем већ пријављен.", + "description": "A paragraph in the filter issue reporter section" + }, + "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" }, - "firstRunDescription": { - "message": "Управо сте инсталирали uBO Lite. Овде можете изабрати подразумевани режим филтрирања који ће се користити на свим сајтовима.\n\nПодразумевано је изабран основни режим јер он не захтева дозволу за читање и мењање података. Ако верујете uBO Lite-у, можете му дати широку дозволу за читање и мењање података како би се подразумевано омогућиле напредније могућности филтрирања за све сајтове.", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "Подразумевани режим филтрирања", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/sv/messages.json b/platform/mv3/extension/_locales/sv/messages.json index 5dcbfc98a8a3f..91178bbcaa7d4 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 effektiv innehållsblockerare. Blockerar annonser, spårare, miners och mer direkt efter den har installerats.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Inställningar", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Utveckla", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Om", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtreringsläge", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "På denna webbplats", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Rapportera ett problem", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Öppna kontrollpanelen", "description": "English: Click to open the dashboard" @@ -56,7 +68,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { - "message": "Domäner med skadlig kod (malware)", + "message": "Skydd mot skadlig programvara, säkerhet", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { @@ -99,13 +111,73 @@ "message": "Externa beroenden (GPLv3-kompatibla):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Välkommen", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Felsökningsinformation", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "För att undvika att belasta volontärer med dubbletter av rapporter, kontrollera att problemet inte redan har rapporterats. Observera: om du klickar på knappen kommer sidans ursprung att skickas till GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Hitta liknande rapporter på GitHub", + "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" }, - "firstRunDescription": { - "message": "Du har precis installerat uBO Lite. Här kan du välja standardfiltreringsläget som ska användas på alla webbplatser.\n\nSom standard är läget Grundläggande valt eftersom det inte kräver behörighet att läsa och ändra data. Om du litar på uBO Lite kan du ge den högre behörighet att läsa och ändra data på alla webbplatser för att som standard aktivera mer avancerade filtreringsmöjligheter för alla webbplatser.", - "description": "Descriptive text shown at first install time only " + "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 på GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Standardfiltreringsläge", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Utvecklarläge", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Aktivera åtkomst till funktioner som är lämpliga för tekniska användare.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Ta bort ett element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Lämna elementzapperläge", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Skapa ett anpassat filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Ta bort ett anpassat filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Visa:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtrera lägesdetaljer", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Anpassade DNR-regler", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR-regler av …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamisk regeluppsättning", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Sessionsregeluppsättning", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Spara", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Ångra", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Importera och lägg till…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Exportera…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Lägg inte till filter från obetrodda källor.", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Antal registrerade regler: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Flytta reglaget för att välja den bästa matchningen", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Välj", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Förhandsgranska", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Skapa", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Välj ett filter nedan för att markera matchande element på webbsidan. Klicka på papperskorgen för att ta bort ett filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/sw/messages.json b/platform/mv3/extension/_locales/sw/messages.json index 4bbb5e389bf08..ef4d2656fc21e 100644 --- a/platform/mv3/extension/_locales/sw/messages.json +++ b/platform/mv3/extension/_locales/sw/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": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +68,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,13 +111,73 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/ta/messages.json b/platform/mv3/extension/_locales/ta/messages.json index 4bbb5e389bf08..ef4d2656fc21e 100644 --- a/platform/mv3/extension/_locales/ta/messages.json +++ b/platform/mv3/extension/_locales/ta/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": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Settings", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "About", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "filtering mode", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Open the dashboard", "description": "English: Click to open the dashboard" @@ -56,7 +68,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,13 +111,73 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", @@ -144,9 +216,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/te/messages.json b/platform/mv3/extension/_locales/te/messages.json index 00008c2bf2ac7..15be21fe8aa7f 100644 --- a/platform/mv3/extension/_locales/te/messages.json +++ b/platform/mv3/extension/_locales/te/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": "An efficient content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "ఐచ్చికాలు", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "మా గురించి", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "వడపోత మోడ్", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "డాష్‌బోర్డ్‌ను తెరవండి", "description": "English: Click to open the dashboard" @@ -56,7 +68,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,13 +111,73 @@ "message": "External dependencies (GPLv3-compatible):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Default filtering mode", @@ -147,6 +219,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 +234,145 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/th/messages.json b/platform/mv3/extension/_locales/th/messages.json index 8d523ba56d2de..ac9c1040a7c16 100644 --- a/platform/mv3/extension/_locales/th/messages.json +++ b/platform/mv3/extension/_locales/th/messages.json @@ -4,87 +4,99 @@ "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" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { - "message": "About", + "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" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "รายงานปัญหาที่เกิดบนเว็บไซต์นี้", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "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,71 +104,275 @@ "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):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "เพื่อเป็นการลดภาระอาสาสมัครจากการรายงานซ้ำซ้อน โปรดตรวจสอบก่อนว่าปัญหาดังกล่าวได้รับการรายงานไปแล้วหรือยัง หมายเหตุ: คลิกที่ปุ่มจะเป็นการส่งต้นทางของหน้าเว็บไปยัง GitHub", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "ค้นหารายงานที่คล้ายกันบน GitHub", + "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": "ตรวจหา uBlock Origin", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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" }, "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": "[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": "เปิดใช้งานการบล๊อกเข็มงวด", "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "การนำทางไปยังเว็บไซต์ที่ไม่พึงประสงค์จะถูกบล็อก และคุณจะได้รับตัวเลือกเพื่อดำเนินการต่อ", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/tr/messages.json b/platform/mv3/extension/_locales/tr/messages.json index b4e410117aedf..d661d089d30e9 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": "Etkili bir içerik engelleyici. Reklamları, izleyicileri, madencileri ve daha fazlasını kurulumdan hemen sonra engeller.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -19,6 +19,10 @@ "message": "Ayarlar", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Geliştir", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Hakkında", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "Filtreleme modu", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "Bu web sitesinde", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Bu sitedeki bir sorunu bildir", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Kontrol panelini aç", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Dış bağlılıklar (GPLv3-uyumlu):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Hoş geldiniz", - "description": "The header text for the welcome message section" + "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 sorun takibi sayfasını kullanın. Bir GitHub hesabı gerekir.", + "description": "First paragraph of 'Filter issues' section in Support pane" + }, + "supportS5H": { + "message": "Sorun giderme bilgisi", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Gönüllüleri benzer raporlar ile bezdirmemek için sorunun zaten bildirilip bildirilmediğine bakın. Not: Butona tıklamak sayfanın temel adresini GitHub'a gönderir.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "GitHub'da 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 can sıkıcı ögeler 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" }, - "firstRunDescription": { - "message": "Az önce uBO Lite'ı indirdiniz. Buradan tüm siteler için varsayılan filtreleme modlarını seçebilirsiniz.\n\nVarsayılan olarak, Basit mod seçilidir çünkü verileri okuma ve yazma izni gerektirmez. uBO Lite'a güveniyorsanız, tüm sitelerde verileri okuma ve yazma izni verebilirsiniz ve daha gelişmiş filtreleme yeteneklerine tüm sitelerde sahip olabilirsiniz.", - "description": "Descriptive text shown at first install time only " + "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, oltalamaya yönlendiriyor", + "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": "GitHub'da yeni rapor oluştur", + "description": "Text for button which open an external webpage in Support pane" }, "defaultFilteringModeSectionLabel": { "message": "Varsayılan filtreleme modu", @@ -147,16 +219,160 @@ "message": "Filtreleme yapılmayacak alan alarının listesi", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[sadece alan adları]\norneksite.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 etkinleştir", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "İstenmeyebilecek sitelere erişim engellenecek ve devam etme seçeneği sunulacaktır.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Geliştirici modu", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Teknik kullanıcılara uygun özelliklere erişime izin ver", + "description": "Short description for a checkbox in the options page" + }, + "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 filtreye 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" + }, + "zapperTipEnter": { + "message": "Öge silme moduna gir", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Öge silme modundan çık", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Özel filtre oluştur", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Özel filtreyi kaldır", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Görünüm:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtreleme modu ayrıntıları", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Özel DNR kuralları", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR kuralları …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dinamik kural seti", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Oturum kural seti", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Kaydet", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Geri al", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "İçe aktar ve ekle…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Dışa aktar…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Güvenilmeyen kaynaklardan içerik eklemeyin", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Kayıtlı kural sayısı: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "En iyi eşleşmeyi seçmek için kaydırıcıyı hareket ettir", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Seç", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Önizle", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Oluştur", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Web sayfasındaki eşleşen öğeleri vurgulamak için aşağıdan bir filtre seçin. Bir filtreyi kaldırmak için çöp kutusuna tıklayın.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/uk/messages.json b/platform/mv3/extension/_locales/uk/messages.json index 5bf1a04b50d6e..fb61435414afe 100644 --- a/platform/mv3/extension/_locales/uk/messages.json +++ b/platform/mv3/extension/_locales/uk/messages.json @@ -19,6 +19,10 @@ "message": "Налаштування", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Розробка", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Про застосунок", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "режим фільтрації", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "На цьому вебсайті", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Повідомити про помилку на цьому вебсайті", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "Відкрити панель керування", "description": "English: Click to open the dashboard" @@ -99,13 +111,73 @@ "message": "Зовнішні залежності (Сумісні з GPLv3)", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Ласкаво просимо", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Усунення проблем", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Щоб не обтяжувати волонтерів повторюваними звітами, переконайтеся, що про проблему ще не повідомлялося.Зауваження: натискання на кнопку призведе до надсилання походження сторінки на GitHub.", + "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" }, - "firstRunDescription": { - "message": "Ви щойно встановили uBO Lite. Тут ви можете вибрати режим фільтрації за замовчуванням, який буде використовуватися на всіх вебсайтах.\n\nЗа замовчуванням вибрано Базовий режим, оскільки він не вимагає дозволу на читання та зміну даних. Якщо ви довіряєте uBO Lite, ви можете надати йому широкий дозвіл на читання та зміну даних на всіх вебсайтах, щоб увімкнути більш розширені можливості фільтрації для всіх вебсайтів за замовчуванням.\n", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "Типовий режим фільтрування", @@ -140,13 +212,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 +232,147 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Режим розробника", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Відкрити доступ до можливостей, які актуальні для технічних користувачів", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Перейти в режим тимчасового приховування елементів", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Вийти з режиму тимчасового приховування елементів", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Створити власний фільтр", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Видалити власний фільтр", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Зберегти", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Повернути", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Імпортувати та додати…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Експортувати…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Кількість зареєстрованих правил: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Вибрати", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Попередній перегляд", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Створити", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/ur/messages.json b/platform/mv3/extension/_locales/ur/messages.json index 2705d513fd105..a93cc1b2a7a92 100644 --- a/platform/mv3/extension/_locales/ur/messages.json +++ b/platform/mv3/extension/_locales/ur/messages.json @@ -19,6 +19,10 @@ "message": "ترتیبات", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Develop", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "تعارف", "description": "appears as tab name in dashboard" @@ -28,63 +32,71 @@ "description": "Link to privacy policy on GitHub (English)" }, "popupFilteringModeLabel": { - "message": "filtering mode", + "message": "فلٹرنگ موڈ", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "Report an issue", + "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 +104,99 @@ "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" }, - "firstRunSectionLabel": { - "message": "Welcome", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Troubleshooting information", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", + "description": "A paragraph in the filter issue reporter section" + }, + "supportFindSpecificButton": { + "message": "Find similar reports on GitHub", + "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" }, - "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", - "description": "Descriptive text shown at first install time only " + "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 on GitHub", + "description": "Text for button which open an external webpage in Support pane" }, "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 +204,175 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Developer mode", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Enables access to features suitable for technical users.", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "Remove an element", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Exit element zapper mode", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "View:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Filtering mode details", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Custom DNR rules", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR rules of …", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Dynamic ruleset", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Session ruleset", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Save", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Revert", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Import and append…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Export…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Do not add content from untrusted sources", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Number of registered rules: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/vi/messages.json b/platform/mv3/extension/_locales/vi/messages.json index 9f796fc5d5ffe..5d3e273a56a23 100644 --- a/platform/mv3/extension/_locales/vi/messages.json +++ b/platform/mv3/extension/_locales/vi/messages.json @@ -19,6 +19,10 @@ "message": "Cài đặt", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "Phát triển", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "Giới thiệu", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "chế độ lọc", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "On this website", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "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 +52,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 +64,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 +92,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,13 +111,73 @@ "message": "Các phụ thuộc bên ngoài (tương thích GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "Chào mừng", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "Thông tin chẩn đoán lỗi", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "Để tránh tạo thêm gánh nặng cho các tình nguyện viên, hãy chắc chắn rằng chưa từng có vấn đề tương tự được báo cáo.", + "description": "A paragraph in the filter issue reporter section" + }, + "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" }, - "firstRunDescription": { - "message": "Bạn vừa cài đặt uBO Lite. Bạn có thể chọn chế độ của bộ lọc mặc định để sử dụng trên tất cả các trang web. Theo mặc định, chế độ Cơ bản được chọn vì chế độ này không yêu cầu quyền đọc và thay đổi dữ liệu. Nếu bạn tin tưởng uBO Lite, bạn có thể cấp cho bộ lọc với quyền rộng rãi để đọc và thay đổi dữ liệu trên tất cả các trang web để kích hoạt khả năng lọc nâng cao hơn cho tất cả các trang web theo mặc định.", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "Chế độ bộ lọc mặc định", @@ -147,6 +219,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 +234,145 @@ "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": "Bật chặn nghiêm ngặt", + "description": "Label for a checkbox in the options page" + }, + "enableStrictBlockLegend": { + "message": "Việc điều hướng đến các trang web có khả năng không mong muốn sẽ bị chặn và bạn sẽ được cung cấp tùy chọn để tiếp tục.", + "description": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "Chế độ nhà phát triển", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "Cho phép truy cập các tính năng dành cho người dùng nâng cao", + "description": "Short description for a checkbox in the options page" + }, + "findListsPlaceholder": { + "message": "Tìm danh sách", + "description": "Placeholder for the input field used to find lists" + }, + "strictblockTitle": { + "message": "Trang bị chặn", + "description": "Webpage title for the strict-blocked page" + }, + "strictblockSentence1": { + "message": "uBO Lite đã ngăn tải trang sau:", + "description": "Sentence used in the strict-blocked page" + }, + "strictblockReasonSentence1": { + "message": "Trang này đã bị chặn vì bộ lọc phù hợp trong {{listname}}.", + "description": "Text informing about what is causing the page to be blocked" + }, + "strictblockRedirectSentence1": { + "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" + }, + "strictblockNoParamsPrompt": { + "message": "không có thông số", + "description": "Label to be used for the parameter-less URL" + }, + "strictblockBack": { + "message": "Quay lại", + "description": "A button to go back to the previous webpage" + }, + "strictblockClose": { + "message": "Đóng cửa sổ này", + "description": "A button to close the current tab" + }, + "strictblockDontWarn": { + "message": "Đừng cảnh báo lại cho tôi về trang web này", + "description": "Label for checkbox in document-blocked page" + }, + "strictblockProceed": { + "message": "Tiến hành", + "description": "A button to navigate to the blocked page" + }, + "zapperTipEnter": { + "message": "Chuyển sang chế độ chặn phần tử tạm thời", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "Thoát khỏi chế độ chặn phần tử tạm thời", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "Create a custom filter", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "Remove a custom filter", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "Xem:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "Chi tiết chế độ chặn", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "Quy tắc DRN tùy chỉnh", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "Quy tắc DRN cho ...", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "Danh sách quy tắc động", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "Danh sách quy tắc phiên", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "Lưu", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "Đặt lại", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "Nhập và thêm vào", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "Xuất...", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "Không thêm các bộ lọc từ các nguồn không đáng tin cậy", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "Số quy tắc đã đăng ký: {count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "Move the slider to select the best match", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "Pick", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "Preview", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "Create", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "Select a filter below to highlight matching elements in the webpage. Click the trash can to remove a filter.", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/zh_CN/messages.json b/platform/mv3/extension/_locales/zh_CN/messages.json index ffbbf9c03badb..ce1a96439c3a4 100644 --- a/platform/mv3/extension/_locales/zh_CN/messages.json +++ b/platform/mv3/extension/_locales/zh_CN/messages.json @@ -19,6 +19,10 @@ "message": "设置", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "开发", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "关于", "description": "appears as tab name in dashboard" @@ -31,8 +35,16 @@ "message": "过滤模式", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "在本网站上", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "报告此网站上的问题", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { - "message": "在仪表板中", + "message": "打开控制面板", "description": "English: Click to open the dashboard" }, "popupMoreButton": { @@ -44,7 +56,7 @@ "description": "Label to be used to hide popup panel sections" }, "3pGroupDefault": { - "message": "预设", + "message": "默认", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAds": { @@ -99,13 +111,73 @@ "message": "外部依赖(与 GPLv3 协议兼容):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "欢迎使用", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "故障排查相关信息", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "请确认该问题未曾上报,以避免加重志愿者负担。", + "description": "A paragraph in the filter issue reporter section" + }, + "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" }, - "firstRunDescription": { - "message": "uBO Lite 现已安装完毕。接下来您可以为网页内容选择默认过滤模式。\n\n预设过滤模式为“基础”,该模式不需要读取或修改网页内容的权限。如果您信任 uBO Lite,您可以授予其用以读取或修改所有网页数据的额外权限,进而默认为所有网站开启高级过滤模式。", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "默认过滤模式", @@ -144,11 +216,15 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "不进行过滤的主机名列表", + "message": "不进行过滤的网站列表。", "description": "A short description for the editable field which lists trusted sites" }, + "noFilteringModePlaceholder": { + "message": "[仅限主机名]\nexample.com\ngames.example\n...", + "description": "Default text for in edit field" + }, "behaviorSectionLabel": { - "message": "操作设置", + "message": "行为", "description": "The header text for the 'Behavior' section" }, "autoReloadLabel": { @@ -156,7 +232,147 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "开发者模式", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "启用访问适合技术用户的功能。", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "进入临时移除元素模式", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "退出临时元素移除模式", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "创建自定义过滤器", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "移除自定义过滤器", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "视图:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "过滤模式详情", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "自定义DNR规则", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR规则来源:", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "动态规则集", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "会话规则集", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "保存", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "还原", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "导入并添加…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "导出…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "请勿添加来自不可信来源的内容", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "已注册规则的数量:", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "移动滑块以选择最佳搭配", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "选择", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "预览", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "创建", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "选择下面的过滤器以突出显示网页中匹配的元素。点击垃圾桶可移除过滤器。", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/_locales/zh_TW/messages.json b/platform/mv3/extension/_locales/zh_TW/messages.json index 99ebc6263ea99..349adc9c9dff2 100644 --- a/platform/mv3/extension/_locales/zh_TW/messages.json +++ b/platform/mv3/extension/_locales/zh_TW/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": { @@ -19,6 +19,10 @@ "message": "設定", "description": "appears as tab name in dashboard" }, + "developPageName": { + "message": "開發", + "description": "appears as tab name in dashboard. Inspired from 'Develop' menu in Safari, see https://developer.apple.com/documentation/safari-developer-tools/develop-menu" + }, "aboutPageName": { "message": "關於", "description": "appears as tab name in dashboard" @@ -31,6 +35,14 @@ "message": "過濾模式", "description": "Label in the popup panel for the current filtering mode" }, + "popupLocalToolsLabel": { + "message": "在此網站上", + "description": "Label in the popup panel for the local tools section" + }, + "popupTipReport": { + "message": "回報此網站的問題", + "description": "Tooltip used for the 'chat' icon in the panel" + }, "popupTipDashboard": { "message": "開啟控制台", "description": "English: Click to open the dashboard" @@ -96,23 +108,83 @@ "description": "Link text to uBO's own filter lists repo" }, "aboutDependencies": { - "message": "外部相依套件(與 GPLv3 相容):", + "message": "外部依存套件(相容 GPLv3):", "description": "Shown in the About pane" }, - "firstRunSectionLabel": { - "message": "歡迎", - "description": "The header text for the welcome message section" + "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" + }, + "supportS5H": { + "message": "疑難排解資訊", + "description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page" + }, + "supportS6P1S1": { + "message": "為避免增加志願者的負擔,請先確認此問題是否已被回報過。請注意:點選按鈕會將本頁的來源傳送到 GitHub。", + "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" }, - "firstRunDescription": { - "message": "您剛安裝了 uBO Lite。您可以在此處選擇要在所有網站上使用的預設過濾模式。\n\n預設情況下將會選取基礎模式,因為其不需要讀取與變更資料的權限。若您信任 uBO Lite,您可以給予其讀取並變更在所有網站上資料的廣泛權限,以便為所有網站啟用更進階的過濾功能。", - "description": "Descriptive text shown at first install time only " + "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" }, "defaultFilteringModeSectionLabel": { "message": "預設過濾模式", "description": "The header text for the default filtering mode section" }, "defaultFilteringModeDescription": { - "message": "預設過濾模式將被每個網站的過濾模式覆寫。您可以根據在該網站上最有效的模式為任何指定的網站調整過濾模式。每種模式都有其優缺點。", + "message": "預設過濾模式將被每個網站的過濾模式覆寫。你可以根據每個網站的情況,調整該網站的過濾模式,以選擇最適合的模式。每種模式都有其優缺點。", "description": "This describes the default filtering mode setting" }, "filteringMode0Name": { @@ -124,7 +196,7 @@ "description": "Name of blocking mode 1" }, "filteringMode2Name": { - "message": "最佳化", + "message": "最佳", "description": "Name of blocking mode 2" }, "filteringMode3Name": { @@ -136,27 +208,171 @@ "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": "Short description for a checkbox in the options page" + }, + "developerModeLabel": { + "message": "開發人員模式", + "description": "Label for a checkbox in the options page" + }, + "developerModeLegend": { + "message": "啟用適合技術使用者使用的功能。", + "description": "Short description for a checkbox in the options page" + }, + "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" + }, + "zapperTipEnter": { + "message": "進入元素臨時移除模式", + "description": "Tooltip for the button used to enter zapper mode" + }, + "zapperTipQuit": { + "message": "離開元素臨時移除模式", + "description": "Tooltip for the button used to exit zapper mode" + }, + "pickerTipEnter": { + "message": "建立自訂過濾器", + "description": "Label for the menu entry to create cosmetic filters" + }, + "unpickerTipEnter": { + "message": "移除自訂過濾器", + "description": "Label for the menu entry to delete cosmetic filters" + }, + "developDropdownLabel": { + "message": "檢視:", + "description": "A label of a dropdown list" + }, + "developOptionFilteringModeDetails": { + "message": "過濾模式詳細資訊", + "description": "An option in a dropdown list" + }, + "developOptionCustomDnrRules": { + "message": "自訂 DNR 規則", + "description": "An option in a dropdown list" + }, + "developOptionDnrRulesOf": { + "message": "DNR 規則……", + "description": "A section header in a dropdown list" + }, + "developOptionDynamicRuleset": { + "message": "動態規則集", + "description": "An option in a dropdown list" + }, + "developOptionSessionRuleset": { + "message": "工作階段規則集", + "description": "An option in a dropdown list" + }, + "saveButton": { + "message": "儲存", + "description": "Text for buttons used to save changes" + }, + "revertButton": { + "message": "還原", + "description": "Text for buttons used to revert changes" + }, + "importAndAppendButton": { + "message": "匯入並加入…", + "description": "Text for buttons used to import and append content" + }, + "exportButton": { + "message": "匯出…", + "description": "Text for buttons used to export content" + }, + "dnrRulesWarning": { + "message": "切勿新增來自不受信任來源的內容", + "description": "Short description of the DNR rules editor pane" + }, + "dnrRulesCountInfo": { + "message": "已登錄規則數:{count}", + "description": "Short sentence to report the number of currently registered DNR rules" + }, + "pickerSliderLabel": { + "message": "移動滑桿以選取最佳符合", + "description": "Label to describe the purpose of the slider" + }, + "pickerPick": { + "message": "挑選", + "description": "Text for the button to re-enter element-picking mode" + }, + "pickerPreview": { + "message": "預覽", + "description": "Text for the button to activate preview mode" + }, + "pickerCreate": { + "message": "建立", + "description": "Text for the button to create the filter" + }, + "unpickerUsage": { + "message": "選取下方的過濾器,突顯網頁中符合條件的元素。按一下回收桶可移除過濾器", + "description": "Summary description on how to use the tool to remove custom filters" } } diff --git a/platform/mv3/extension/css/dashboard-common.css b/platform/mv3/extension/css/dashboard-common.css index 41d641621e125..ebef32f609a2d 100644 --- a/platform/mv3/extension/css/dashboard-common.css +++ b/platform/mv3/extension/css/dashboard-common.css @@ -1,3 +1,14 @@ +body { + align-items: center; + box-sizing: border-box; + display: flex; + flex-direction: column; + padding: 0 var(--default-gap-xxsmall); + } +body > * { + width: min(640px, 100%); + } + h2, h3 { margin: 1em 0; } @@ -7,9 +18,11 @@ h2 { h3 { font-size: 16px; } + a { text-decoration: none; } + .fa-icon.info { color: var(--info0-ink); fill: var(--info0-ink); @@ -26,9 +39,15 @@ a { color: var(--info3-ink); fill: var(--info3-ink); } + input[type="number"] { width: 5em; } + +input[type="file"] { + display: none; + } + @media (max-height: 640px), (max-height: 800px) and (max-width: 480px) { .body > p, .body > ul { diff --git a/platform/mv3/extension/css/dashboard.css b/platform/mv3/extension/css/dashboard.css index e98bcc9a40497..a33c13f426d9a 100644 --- a/platform/mv3/extension/css/dashboard.css +++ b/platform/mv3/extension/css/dashboard.css @@ -1,13 +1,4 @@ -body { - align-items: center; - box-sizing: border-box; - display: flex; - flex-direction: column; - } -body > * { - width: min(640px, 100%); - } -#dashboard-nav { +nav { background-color: var(--surface-1); border: 0; border-bottom: 1px solid var(--border-1); @@ -20,7 +11,7 @@ body > * { top: 0; z-index: 100; } -.tabButton { +nav > .tabButton { background-color: transparent; border: 0; border-bottom: 3px solid transparent; @@ -33,42 +24,49 @@ body > * { text-decoration: none; white-space: nowrap; } -.tabButton:focus { +nav > .tabButton:focus { outline: 0; } -.tabButton:hover { +nav > .tabButton:hover { background-color: var(--dashboard-tab-hover-surface); border-bottom-color: var(--dashboard-tab-hover-border); } body[data-pane="settings"] #dashboard-nav .tabButton[data-pane="settings"], +body[data-pane="rulesets"] #dashboard-nav .tabButton[data-pane="rulesets"], +body[data-pane="develop"] #dashboard-nav .tabButton[data-pane="develop"], body[data-pane="about"] #dashboard-nav .tabButton[data-pane="about"] { background-color: var(--dashboard-tab-active-surface); border-bottom: 3px solid var(--dashboard-tab-active-ink); color: var(--dashboard-tab-active-ink); fill: var(--dashboard-tab-active-ink); } +body:not([data-develop="true"]) #dashboard-nav .tabButton[data-pane="develop"] { + display: none; + } body > section { display: none; + padding-bottom: 2rem; } body[data-pane="settings"] > section[data-pane="settings"], +body[data-pane="rulesets"] > section[data-pane="rulesets"], +body[data-pane="develop"] > section[data-pane="develop"], body[data-pane="about"] > section[data-pane="about"] { display: block; } /* high dpi devices */ :root.hidpi .tabButton { - font-family: Metropolis, sans-serif; font-weight: 600; letter-spacing: 0.5px; } /* touch-screen devices */ -:root.mobile #dashboard-nav { +:root.mobile nav { flex-wrap: nowrap; overflow-x: auto; } -:root.mobile #dashboard-nav .logo { +:root.mobile nav .logo { display: none; } diff --git a/platform/mv3/extension/css/develop.css b/platform/mv3/extension/css/develop.css new file mode 100644 index 0000000000000..55816b6d657c8 --- /dev/null +++ b/platform/mv3/extension/css/develop.css @@ -0,0 +1,168 @@ +body[data-pane="develop"] { + height: 100vh; + } + +section[data-pane="develop"] { + display: none; + flex-grow: 1; + overflow: hidden; + } + +section[data-pane="develop"] > div { + display: flex; + flex-direction: column; + height: 100%; + } + +section[data-pane="develop"] > div > * { + margin-bottom: 0; + margin-top: 1em; + } + +#cm-container { + flex-grow: 1; + font-size: var(--monospace-size); + overflow: hidden; + } + +/* https://discuss.codemirror.net/t/how-to-set-max-height-of-the-editor/2882/2 */ +#cm-container .cm-editor { + background-color: var(--surface-0); + height: 100%; + } + +#cm-container .cm-editor .cm-line:has(.ubol-boundary) { + background-image: url('line-hor-dashed.png'), url('line-hor-dashed.png'); + background-position: left 3px, left calc(100% - 3px); + background-repeat: repeat-x; + } +#cm-container .cm-editor { + color: var(--ink-1); + } +:root.dark #cm-container .cm-editor { + color: var(--ink-2); + } +#cm-container .cm-editor .cm-line .ubol-comment { + color: #ba5300; + } +:root.dark #cm-container .cm-editor .cm-line .ubol-comment { + color: #fa7000; + } +#cm-container .cm-editor .cm-line .ubol-keyword { + color: #ae42be; + } +:root.dark #cm-container .cm-editor .cm-line .ubol-keyword { + color: #ea59ff; + } +#cm-container .cm-editor .cm-line .ubol-literal { + color: #168156; + } +:root.dark #cm-container .cm-editor .cm-line .ubol-literal { + color: #1dae74; + } +#cm-container .cm-editor .cm-line.badline:not(.cm-activeLine) { + background-color: color-mix(in srgb, var(--info3-ink) 15%, transparent 85%); + } + +#cm-container .cm-editor .cm-line .badmark { + text-decoration: underline var(--cm-negative) wavy; + text-decoration-skip-ink: none; + } + +#cm-container .cm-editor .cm-panel.cm-search { + display: flex; + flex-wrap: wrap; + font-family: sans-serif; + font-size: var(--font-size); + gap: 0.5em 1em; + padding: 0.5em 1.5em 0.5em 0.5em; + } + +#cm-container .cm-editor .cm-panel.cm-search > * { + margin: 0; + } + +#cm-container .cm-editor .cm-panel.cm-search .cm-textfield, +#cm-container .cm-editor .cm-panel.cm-search .cm-button, +#cm-container .cm-editor .cm-panel.cm-search label { + background-image: inherit; + border: inherit; + flex-grow: 0; + font-size: var(--button-font-size); + min-height: calc(var(--button-font-size) * 1.8); + } + +#cm-container .cm-editor .cm-panel .warning { + color: var(--info3-ink); + } + +#cm-container .cm-editor .cm-panel.io-panel { + background-color: var(--surface-1); + box-sizing: border-box; + display: inline-flex; + gap: 0.25em; + padding: 0.25em; + padding-inline-start: 0; + width: 100%; + } +#cm-container .cm-editor .cm-panel.io-panel button { + min-height: 30px; + } +#cm-container .cm-editor .cm-panel.io-panel button#revert { + margin-inline-end: 1em; + } +#cm-container .cm-editor .cm-panel.io-panel:not([data-io~="apply"]) button#apply { + display: none; + } +#cm-container .cm-editor .cm-panel.io-panel:not([data-io~="revert"]) button#revert { + display: none; + } +#cm-container .cm-editor .cm-panel.io-panel:not([data-io~="import"]) button#import { + display: none; + } +#cm-container .cm-editor .cm-panel.io-panel:not([data-io~="export"]) button#export { + display: none; + } + +#cm-container .cm-editor .cm-panel.info-panel { + display: flex; + flex-wrap: nowrap; + font-size: var(--font-size); + padding: var(--default-gap-xxsmall) var(--default-gap-xsmall); + } +#cm-container .cm-editor .cm-panel.info-panel .info { + flex-grow: 1; + overflow: auto; + } +#cm-container .cm-editor .cm-panel.info-panel .close { + cursor: default; + flex-shrink: 0; + padding-inline-start: 1em; + } +#cm-container .cm-editor .cm-panel.info-panel .close::after { + content: '\2715'; + } + +#cm-container .cm-editor .cm-panel.summary-panel { + background-color: color-mix(in srgb, var(--info1-ink) 15%, transparent 85%); + gap: 1em; + } +#cm-container .cm-editor .cm-panel.summary-panel .info { + flex-shrink: 0; + } + +#cm-container .cm-editor .cm-panel.feedback-panel { + background-color: color-mix(in srgb, var(--info3-ink) 15%, transparent 85%); + white-space: pre; + max-height: 10cqh; + } + +#cm-container .cm-editor .cm-gutterElement { + cursor: default; + user-select: none; + } + +#cm-container .cm-editor .cm-tooltip .badmark-tooltip { + background-color: color-mix(in srgb, var(--info3-ink) 15%, transparent 85%); + padding: var(--default-gap-xxsmall) var(--default-gap-xsmall); + } \ No newline at end of file diff --git a/platform/mv3/extension/css/filtering-mode.css b/platform/mv3/extension/css/filtering-mode.css index fecb1ac3cf406..2554bdc3ac385 100644 --- a/platform/mv3/extension/css/filtering-mode.css +++ b/platform/mv3/extension/css/filtering-mode.css @@ -1,19 +1,24 @@ +:root { + --filtering-mode-button-size: 60px; /* should be multiple of 4 */ + --filtering-mode-slider-width: calc(4 * var(--filtering-mode-button-size) + 3px); + } + .filteringModeSlider { align-items: center; + container-type: size; display: flex; - height: 60px; + height: var(--filtering-mode-button-size); justify-content: center; position: relative; - width: 240px; + width: var(--filtering-mode-slider-width); } .filteringModeButton { background-color: var(--surface-1); - box-sizing: border-box; - border-radius: 30% 15% / 15% 30%; - height: 100%; + border-radius: 20%; + height: var(--filtering-mode-button-size); position: absolute; - width: 25%; + width: var(--filtering-mode-button-size); z-index: 10; } @@ -22,9 +27,8 @@ border: 4px solid var(--accent-surface-1); border-radius: inherit; box-sizing: border-box; - height: calc(100% - 2px); - margin: 1px; - width: calc(100% - 2px); + height: 100%; + width: 100%; } .filteringModeSlider.moving .filteringModeButton > div, @@ -40,9 +44,13 @@ .filteringModeSlider span[data-level] { background-color: var(--accent-surface-1); display: inline-flex; + flex-shrink: 0; height: 30%; margin-left: 1px; - width: 25%; + width: var(--filtering-mode-button-size); + } +.filteringModeSlider span[data-level]:first-of-type { + margin-left: 0; } .filteringModeSlider.moving span[data-level] { @@ -53,38 +61,49 @@ left: 0; } .filteringModeSlider[data-level="1"] .filteringModeButton { - left: 25%; + left: calc(var(--filtering-mode-button-size) + 1px); } .filteringModeSlider[data-level="2"] .filteringModeButton { - left: 50%; + left: calc(var(--filtering-mode-button-size) * 2 + 2px); } .filteringModeSlider[data-level="3"] .filteringModeButton { - left: 75%; + left: calc(var(--filtering-mode-button-size) * 3 + 3px); + } + +[dir="rtl"] .filteringModeSlider span[data-level] { + margin-left: 0; + margin-right: 1px; + } +[dir="rtl"] .filteringModeSlider span[data-level]:first-of-type { + margin-right: 0; } [dir="rtl"] .filteringModeSlider[data-level="0"] .filteringModeButton { - left: 75%; + right: 0; } [dir="rtl"] .filteringModeSlider[data-level="1"] .filteringModeButton { - left: 50%; + right: calc(var(--filtering-mode-button-size) + 1px); } [dir="rtl"] .filteringModeSlider[data-level="2"] .filteringModeButton { - left: 25%; + right: calc(var(--filtering-mode-button-size) * 2 + 2px); } [dir="rtl"] .filteringModeSlider[data-level="3"] .filteringModeButton { - left: 0; + right: calc(var(--filtering-mode-button-size) * 3 + 3px); } .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/line-hor-dashed.png b/platform/mv3/extension/css/line-hor-dashed.png new file mode 100644 index 0000000000000..cb124a2b5426c Binary files /dev/null and b/platform/mv3/extension/css/line-hor-dashed.png differ diff --git a/platform/mv3/extension/css/matched-rules.css b/platform/mv3/extension/css/matched-rules.css new file mode 100644 index 0000000000000..177f312730db3 --- /dev/null +++ b/platform/mv3/extension/css/matched-rules.css @@ -0,0 +1,31 @@ + +#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; +} +html.dark .matchInfo:nth-of-type(2n) { + background-color: #444; +} + +.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/picker-ui.css b/platform/mv3/extension/css/picker-ui.css new file mode 100644 index 0000000000000..8e86f93d0a10a --- /dev/null +++ b/platform/mv3/extension/css/picker-ui.css @@ -0,0 +1,144 @@ +:root#ubol-picker { + --ubol-overlay-fill: rgba(255,64,64,0.10); + --ubol-overlay-border: #F00; +} + +#ubol-picker.paused svg#overlay { + cursor: not-allowed; +} + +:root aside { + background-color: var(--surface-1); + border: 1px solid var(--border-2); + max-width: min(32rem, 100vw - 4px); + min-width: min(24rem, 100vw - 4px); + row-gap: 1em; + width: min(32rem, 100vw - 4px); +} + +#ubol-picker aside > section:last-of-type { + margin-block-end: 0; +} +#ubol-picker aside > section:not(#windowbar,#moreOrLess) { + padding: 0 4px; +} + +#ubol-picker[data-view="0"] aside section[data-view="1"], +#ubol-picker[data-view="0"] aside section[data-view="2"] { + display: none; +} +#ubol-picker[data-view="1"] aside section[data-view="2"] { + display: none; +} + +#ubol-picker:not(.paused) aside > section:not(#windowbar) { + display: none; +} + +#ubol-picker textarea { + border: 0; + box-sizing: border-box; + min-height: 5em; + resize: none; + width: 100%; +} +#ubol-picker.mobile textarea { + height: unset; +} +#ubol-picker .resultsetWidgets { + color: var(--ink-2); + display: flex; + flex-direction: column; + font-size: small; + gap: 0.25em; +} +#ubol-picker .resultsetWidgets > span:first-of-type { + display: flex; + margin: 0 1em; +} +#ubol-picker .resultsetWidgets label { + flex-grow: 1; +} +#ubol-picker .resultsetWidgets #resultsetCount { + display: inline-block; + text-align: right; + width: 8ch; +} + +#ubol-picker #toolbar { + display: flex; + justify-content: space-between; +} +#ubol-picker #toolbar button { + min-width: 5em; +} + +#ubol-picker #candidateFilters { + font-family: monospace; + font-size: small; + max-height: min(20em, 30vh); + min-height: 6em; + overflow-y: auto; + word-break: break-all; +} +#ubol-picker #candidateFilters ul { + margin: 0; + padding-inline-start: calc(2ch + 4px); + user-select: none; + -webkit-user-select: none; +} +#ubol-picker #candidateFilters ul > li { + list-style-type: '\25A0\00A0'; +} +#ubol-picker #candidateFilters ul >li:has(:not(span.on)) { + list-style-type: '\25A1\00A0'; +} +#ubol-picker #candidateFilters ul > li:nth-of-type(2n+1) { + background-color: var(--surface-2); +} +#ubol-picker #candidateFilters ul > li > span { + border: 1px solid transparent; + padding: 1px 2px; +} +#ubol-picker #candidateFilters ul > li > span.on { + background-color: var(--accent-surface-1); + color: var(--accent-ink-1);} +#ubol-picker #candidateFilters ul > li > span:hover { + border: 1px solid var(--ink-1); +} + +#ubol-picker #moreOrLess { + color: var(--ink-2); + column-gap: 0; + display: grid; + font-size: small; + grid-template: auto / 1fr 1fr; + justify-items: stretch; + user-select: none; + -webkit-user-select: none; + white-space: nowrap; +} +#ubol-picker #moreOrLess > span { + cursor: pointer; + padding: var(--default-gap-xxsmall) var(--default-gap-xsmall); +} +#ubol-picker #moreOrLess > span:last-of-type { + text-align: end; +} +#ubol-picker[data-view="2"] aside #moreOrLess > span:first-of-type { + visibility: hidden; +} +#ubol-picker[data-view="0"] aside #moreOrLess > span:last-of-type { + visibility: hidden; +} +#ubol-picker.desktop aside #moreOrLess > span:hover { + background-color: var(--surface-2); +} + +#ubol-picker.preview #toolbar #preview { + color: var(--accent-ink-1); + background-color: var(--accent-surface-1); +} +#ubol-picker.preview #overlay path { + display: none; +} diff --git a/platform/mv3/extension/css/popup.css b/platform/mv3/extension/css/popup.css index 385a051652f82..b2f208a7ea754 100644 --- a/platform/mv3/extension/css/popup.css +++ b/platform/mv3/extension/css/popup.css @@ -2,49 +2,45 @@ .fa-icon.fa-icon-badged > .fa-icon-badge { bottom: auto; top: -20%; - } +} + +:root { + --popup-min-width: calc( + var(--filtering-mode-slider-width) + + var(--filtering-mode-button-size) / 2 + ); +} :root body, :root.mobile body { - --font-size: 14px; --popup-gap: var(--font-size); --popup-gap-thin: calc(0.5 * var(--popup-gap)); --popup-gap-extra-thin: calc(0.25 * var(--popup-gap)); - --popup-main-min-width: 18em; - --popup-firewall-min-width: 30em; - --popup-rule-cell-width: 5em; - font-size: var(--font-size); - line-height: 20px; - min-width: 100%; - } + min-width: var(--popup-min-width); +} :root body.loading { - opacity: 0; - } + visibility: hidden; +} a { color: var(--ink-1); fill: var(--ink-1); text-decoration: none; - } +} :focus { outline: 0; - } +} #main { align-self: flex-start; display: flex; flex-direction: column; - max-width: 340px; - min-width: 100%; - } +} :root.portrait #main { align-self: inherit; - } +} hr { - border: 0; - border-top: 1px solid var(--hr-ink); - margin: 0; - padding: 0; - } + margin: 0.5em 0; +} #hostname { align-items: center; @@ -55,222 +51,147 @@ hr { padding: 0 var(--popup-gap-extra-thin); text-align: center; word-break: break-all; - } +} #hostname > span { word-break: break-all; - } +} #hostname > span + span { font-weight: 600; - } +} + +body[data-forbid~="filteringMode"] .filteringModeSlider { + pointer-events: none; +} +body[data-forbid~="zapper"] #gotoZapper, +body[data-forbid~="picker"] #gotoPicker, +body[data-forbid~="picker"] #gotoUnpicker, +body[data-forbid~="report"] #gotoReport, +body[data-forbid~="zapper"][data-forbid~="picker"][data-forbid~="report"] .localTools { + display: none; +} +body[data-forbid~="dashboard"] .globalTools { + display: none; +} #filteringModeText { color: var(--ink-3); - margin: var(--default-gap-small); - margin-top: 0; + margin-bottom: var(--popup-gap-thin); text-align: center; text-transform: lowercase; - } +} #filteringModeText > span { color: var(--accent-surface-1); - } +} #filteringModeText > span:nth-of-type(2) { display: none; - } +} #filteringModeText > span:nth-of-type(2):not(:empty) { display: inline; - } +} #filteringModeText > span:nth-of-type(2):not(:empty)::before { content: '\2002\2192\2002'; - } +} [dir="rtl"] #filteringModeText > span:nth-of-type(2):not(:empty)::before { content: '\2002\2190\2002'; - } +} .filteringModeSlider { align-self: center; - margin: var(--popup-gap); - width: calc(var(--popup-main-min-width) - 1em); - } + margin: var(--popup-gap) 0; +} -.rulesetTools { - background-color: transparent; - border: 0; - box-sizing: border-box; - display: flex; - flex-direction: column; - justify-content: space-evenly; - width: 25%; - } -.rulesetTools [id] { - background-color: var(--popup-ruleset-tool-surface); - border-radius: 4px; - cursor: pointer; - fill: var(--popup-ruleset-tool-ink); - flex-grow: 1; - font-size: 2.2em; - padding: 0; - visibility: hidden; - } -.rulesetTools [id]:not(:first-of-type) { - margin-block-start: 1px; - } -.rulesetTools [id] > svg { - fill: var(--ink-4); - } body.needReload #refresh { visibility: visible; - } +} -#rulesetStats { - padding: 0 var(--popup-gap-thin); - } -#rulesetStats .rulesetDetails h1 { - font-size: 1em; - font-weight: normal; - margin: 0.5em 0 0.25em 0; - } -#rulesetStats .rulesetDetails p { +.toolMenu { + border-top: 1px solid var(--surface-2); + display: flex; + flex-direction: column; + margin: 0.5em 0; + padding-top: 0.5em; +} +:root:not(.isHTTP) .needHTTP { + display: none; +} +.toolMenu > label { + font-size: 90%; color: var(--ink-2); - font-size: var(--font-size-smaller); - margin: 0.25em 0 0.5em 0.5em; - } - -.itemRibbon { - column-gap: var(--popup-gap); - display: grid; - grid-auto-columns: 1fr; - grid-auto-flow: column; - grid-template: auto / 1fr 1fr; - margin: var(--popup-gap); - } -.itemRibbon > span + span { - text-align: end; - } + line-height: calc(var(--font-size) * 1.8); + margin-inline-start: 0.5em; +} +.toolMenu > .tool { + cursor: pointer; + display: flex; + padding: 0.5em 0.5em 0.5em 0; + unicode-bidi: embed; +} +.toolMenu > .tool:hover { + color: var(--ink-1); + fill: var(--ink-1); +} +.toolMenu > .tool:not(.enabled) { + display: none; +} +.toolMenu > .tool .fa-icon { + font-size: 1.4em; + min-width: 1.4em; +} +.toolMenu > .tool [data-i18n] { + flex-grow: 1; +} .toolRibbon { - align-items: center; background-color: var(--popup-toolbar-surface); - display: grid; - grid-auto-columns: 1fr; - grid-auto-flow: column; - grid-template: auto / repeat(5, 1fr); - justify-items: center; + display: flex; + flex-wrap: nowrap; + justify-content: space-between; + margin: 0; white-space: normal; - } +} .toolRibbon .tool { cursor: pointer; display: flex; flex-direction: column; - font-size: 1.4em; min-width: 32px; - padding: var(--popup-gap) - var(--popup-gap-thin); + padding: var(--default-gap-small); unicode-bidi: embed; visibility: hidden; - } +} .toolRibbon .tool:hover { color: var(--ink-1); fill: var(--ink-1); - } +} .toolRibbon .tool.enabled { visibility: visible; - } +} +.toolRibbon .tool.fa-icon { + font-size: 1.4em; +} +:root.mobile .toolRibbon .tool.fa-icon { + font-size: 1.6em; +} .toolRibbon .tool .caption { font: 10px/12px sans-serif; margin-top: 6px; text-align: center; - } -body.mobile.no-tooltips .toolRibbon .tool { - font-size: 1.6em; - } -.toolRibbon.genericTools { - margin-bottom: 0; - } - -#moreOrLess { - column-gap: 0; - display: grid; - grid-template: auto / 1fr 1fr; - justify-items: stretch; - margin: 1px 0 0 0; - } -#moreOrLess > span { - cursor: pointer; - margin: 0; - padding: var(--popup-gap-thin) var(--popup-gap); - user-select: none; - white-space: nowrap; - } -#moreButton .fa-icon { - transform: rotate(180deg); - } -#lessButton { - border-inline-start: 1px solid var(--surface-1); - text-align: end; - } -body[data-section="a b"] #moreButton { - pointer-events: none; - visibility: hidden; - } -body[data-section=""] #lessButton { - pointer-events: none; - visibility: hidden; - } -body:not([data-section~="a"]) [data-section="a"] { +} +:root:not(.mobile) .toolRibbon .caption { display: none; - } -body:not([data-section~="b"]) [data-section="b"] { - display: none; - } - -/* configurable UI elements */ -:root:not(.mobile) .toolRibbon .caption, -:root.mobile body.no-tooltips .toolRibbon .caption, -:root.mobile body[data-ui~="-captions"] .toolRibbon .caption { - display: none; - } -:root.mobile .toolRibbon .caption, -:root:not(.mobile) body[data-ui~="+captions"] .toolRibbon .caption { - display: inherit; - } -:root:not(.mobile) .toolRibbon .tool, -:root.mobile body.no-tooltips .toolRibbon .tool, -:root.mobile body[data-ui~="-captions"] .toolRibbon .tool { - padding: var(--popup-gap) var(--popup-gap-thin); - } -:root.mobile #moreOrLess > span { - padding: var(--popup-gap); - } +} /* horizontally-constrained viewport */ :root.portrait body { overflow-y: auto; width: 100%; - } +} :root.portrait #main { max-width: unset; - } +} /* mouse-driven devices */ :root.desktop { display: flex; - } -:root.desktop body { - --popup-gap: calc(var(--font-size) * 0.875); - } -:root.desktop .rulesetTools [id]:hover { - background-color: var(--popup-ruleset-tool-surface-hover); - } -:root.desktop .rulesetTools [id]:hover > svg { - fill: var(--ink-2); - } +} :root.desktop .tool:hover { background-color: var(--popup-toolbar-surface-hover); - } -:root.desktop #moreOrLess > span:hover { - background-color: var(--surface-2); - /* background-color: var(--popup-toolbar-surface-hover); */ - } - -#templates { - display: none; - } +} diff --git a/platform/mv3/extension/css/report.css b/platform/mv3/extension/css/report.css new file mode 100644 index 0000000000000..0f8ad31107c89 --- /dev/null +++ b/platform/mv3/extension/css/report.css @@ -0,0 +1,11 @@ +:root .safari { + display: none; +} + +:root.safari .safari { + display: initial; +} + +.warning { + color: var(--info2-ink); +} \ No newline at end of file diff --git a/platform/mv3/extension/css/settings.css b/platform/mv3/extension/css/settings.css index 2e727fc0e33ab..4e6618da67215 100644 --- a/platform/mv3/extension/css/settings.css +++ b/platform/mv3/extension/css/settings.css @@ -1,33 +1,37 @@ -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } +:root { + --filtering-mode-button-size: 32px; } -legend { - color: var(--ink-3); - font-size: var(--font-size-smaller); - padding: var(--default-gap-xxsmall); - } -body .firstRun { - display: none; - } -body.firstRun .firstRun { - background-color: rgb(var(--dashboard-highlight-surface-rgb)); - display: block; - padding: 8px; + +body.loading { + visibility: hidden; } 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; + } +body[data-forbid~="develop"] #developerMode { + 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 { @@ -41,6 +45,9 @@ section > div { display: flex; flex-direction: column; } +.filteringModeCard:hover { + background-color: color-mix(in hsl, var(--surface-1) 75%, var(--surface-0) 25%); + } .filteringModeCard:has(.radio > [type="radio"]:checked) { background-color: var(--surface-0); } @@ -67,100 +74,126 @@ section > div { white-space: pre-line; } .filteringModeSlider { - height: calc(60px / 2); pointer-events: none; - width: calc(240px / 2); } h3[data-i18n="filteringMode0Name"]::first-letter { text-transform: capitalize; } #trustedSites { - box-sizing: border-box; - height: 6rem; - resize: vertical; - width: 100%; + background-color: var(--surface-0); + border: 1px solid var(--surface-3); + font-size: var(--monospace-size); + min-height: 8rem; } -#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; } -.groupEntry.hideUnused:not([data-groupkey="user"]) .geDetails::before { - content: '+'; +section[data-pane="rulesets"] > div:first-of-type > p:last-of-type { + margin-bottom: 0; } -.groupEntry { - margin: 0.5em 0; +.listEntry { + display: flex; + flex-direction: column; + } +.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); } -.groupEntry:not([data-groupkey="user"]) .listEntry:not(.isDefault).unused { +.listEntry.hideUnused > .listEntries > .listEntry:not(.isDefault):has(> .detailbar input:not(:checked)) { + display: none; + } +.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/css/tool-overlay-ui.css b/platform/mv3/extension/css/tool-overlay-ui.css new file mode 100644 index 0000000000000..e049502388fe5 --- /dev/null +++ b/platform/mv3/extension/css/tool-overlay-ui.css @@ -0,0 +1,99 @@ +:root { + --ubol-overlay-fill: rgba(255,255,255,0.2); + --ubol-overlay-border: #FFF; + --ubol-overlay-canvas: rgba(128,128,128,0.3); +} +:root.dark aside { + color-scheme: dark; +} + +:root, +:root > body { + background: transparent; + height: 100vh; + height: 100svh; + margin: 0; + overflow: hidden; + width: 100vw; +} +:root > body.loading { + visibility: hidden; +} + +:root :focus { + outline: none; +} + +svg#overlay { + cursor: crosshair; + box-sizing: border-box; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +svg#overlay > path:first-child { + fill: var(--ubol-overlay-canvas); + fill-rule: evenodd; +} +svg#overlay > path + path { + stroke: var(--ubol-overlay-border); + stroke-width: 1.5px; + fill: var(--ubol-overlay-fill); +} + +:root aside { + box-sizing: border-box; + cursor: default; + display: flex; + flex-direction: column; + position: fixed; + z-index: 100; +} +:root body[dir="rtl"] aside { + left: 2px; + right: unset; +} + +:root.minimized aside > section:not(#windowbar) { + display: none !important; +} +:root.minimized aside { + min-width: min(12em, 100vw - 4px); + width: min(12em, 100vw - 4px); +} + +:root aside #windowbar { + border-bottom: 1px solid var(--border-1); + display: flex; +} +:root aside #windowbar > div { + fill: none; + height: 2em; + stroke: var(--ink-1); + stroke-width: 2px; + width: 2em; +} +:root.minimized aside #windowbar > div { + height: 3em; + width: 3em; +} +:root.minimized aside #windowbar > #minimize svg > path, +#windowbar #minimize svg > rect { + display: none; +} +:root.minimized aside #windowbar > #minimize svg > rect { + display: initial; +} +:root #windowbar > #move { + align-items: center; + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAYAAACtBE5DAAAAFElEQVQI12NgwAfKy8v/M5ANYLoBshgEyQo6H9UAAAAASUVORK5CYII='); + cursor: grab; + display: flex; + justify-content: center; + flex-grow: 1; +} +:root #windowbar > div:hover { + background-color: var(--surface-2) +} diff --git a/platform/mv3/extension/css/unpicker-ui.css b/platform/mv3/extension/css/unpicker-ui.css new file mode 100644 index 0000000000000..c05bf6eaaaa18 --- /dev/null +++ b/platform/mv3/extension/css/unpicker-ui.css @@ -0,0 +1,62 @@ +:root#ubol-unpicker { + --ubol-overlay-fill: rgba(64,255,64,0.10); + --ubol-overlay-border: #0F0; +} + +#ubol-unpicker svg#overlay { + cursor: not-allowed; +} + +:root aside { + background-color: var(--surface-1); + border: 1px solid var(--border-2); + max-height: 40vh; + max-width: min(32rem, 100vw - 4px); + min-width: min(24rem, 100vw - 4px); + width: min(32rem, 100vw - 4px); +} + +#ubol-unpicker aside > section:not(#windowbar) { + margin: 1em 1em 0 1em; +} +#ubol-unpicker aside > section:not(#windowbar):last-of-type { + margin-bottom: 1em; +} +#ubol-unpicker aside > section [data-i18n="unpickerUsage"] { + color: var(--ink-2); + font-size: small; +} + +#ubol-unpicker #customFilters { + font-family: monospace; +} +#ubol-unpicker .customFilter { + display: flex; +} +#ubol-unpicker .customFilter:nth-of-type(2n+1) { + background-color: var(--surface-2); +} +#ubol-unpicker .customFilter > span.selector { + flex-grow: 1; + font-size: small; + padding: 0.5em; +} +#ubol-unpicker .customFilter.on > span.selector { + background-color: var(--accent-surface-1); + color: var(--accent-ink-1); +} +#ubol-unpicker .customFilter.removed > span.remove { + display: none; +} +#ubol-unpicker .customFilter.removed > span.selector { + pointer-events: none; + text-decoration-line: line-through; +} +#ubol-unpicker .customFilter > span.fa-icon { + flex-shrink: 0; + font-size: 1.25em; + padding: 0 0.5em; +} +#ubol-unpicker .customFilter:not(.removed) > span.undo { + display: none; +} diff --git a/platform/mv3/extension/css/zapper-ui.css b/platform/mv3/extension/css/zapper-ui.css new file mode 100644 index 0000000000000..93c3227169a7c --- /dev/null +++ b/platform/mv3/extension/css/zapper-ui.css @@ -0,0 +1,29 @@ +:root#ubol-zapper { + --quit-button-size: max(4em, min(6em, calc(100vw / 8), calc(100vh / 8))); + --ubol-overlay-fill: rgba(255,255,63,0.10); + --ubol-overlay-border: #FF0; +} + +#ubol-zapper aside { + gap: 2px; + right: 2px; + top: 50%; + transform: translateY(-50%); +} + +#ubol-zapper aside > div { + background-color: var(--surface-1); + border: 1px solid rgba(0,0,0,0.5); + box-sizing: border-box; + fill: none; + stroke: var(--ink-1); + stroke-width: 2px; + width: var(--quit-button-size); + height: var(--quit-button-size); +} +#ubol-zapper aside > div:hover { + background-color: var(--surface-2) +} +:root:not(.mobile) #pick { + display: none; +} \ No newline at end of file diff --git a/platform/mv3/extension/dashboard.html b/platform/mv3/extension/dashboard.html index d2dc918d980db..d45605c657e69 100644 --- a/platform/mv3/extension/dashboard.html +++ b/platform/mv3/extension/dashboard.html @@ -3,6 +3,7 @@ + @@ -12,17 +13,20 @@ + - + - + -
+
+
@@ -32,11 +36,6 @@

-
-

-

-
-

@@ -87,36 +86,33 @@

+

+

- +

+ +
-

-

_

-

-

+

+

- +
+
+ +
-

-
-

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

+   +

+
@@ -137,20 +133,79 @@

+
+
+

+            
+
+
+
+ + + home + + +
+ + +
+ + + + + + + diff --git a/platform/mv3/extension/img/icon_128_off.png b/platform/mv3/extension/img/icon_128_off.png new file mode 100644 index 0000000000000..f878785974fcf Binary files /dev/null and b/platform/mv3/extension/img/icon_128_off.png differ diff --git a/platform/mv3/extension/img/icon_16_off.png b/platform/mv3/extension/img/icon_16_off.png new file mode 100644 index 0000000000000..5373e8229dfb9 Binary files /dev/null and b/platform/mv3/extension/img/icon_16_off.png differ diff --git a/platform/mv3/extension/img/icon_32_off.png b/platform/mv3/extension/img/icon_32_off.png new file mode 100644 index 0000000000000..04f1a67a775d4 Binary files /dev/null and b/platform/mv3/extension/img/icon_32_off.png differ diff --git a/platform/mv3/extension/img/icon_512.png b/platform/mv3/extension/img/icon_512.png new file mode 100644 index 0000000000000..b5f29734802ee Binary files /dev/null and b/platform/mv3/extension/img/icon_512.png differ diff --git a/platform/mv3/extension/img/icon_64_off.png b/platform/mv3/extension/img/icon_64_off.png new file mode 100644 index 0000000000000..d9a22955a509c Binary files /dev/null and b/platform/mv3/extension/img/icon_64_off.png differ diff --git a/platform/mv3/extension/js/action.js b/platform/mv3/extension/js/action.js new file mode 100644 index 0000000000000..811fe101c0b1b --- /dev/null +++ b/platform/mv3/extension/js/action.js @@ -0,0 +1,110 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2022-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { matchesFromHostnames, strArrayEq } from './utils.js'; +import { browser } from './ext.js'; + +/******************************************************************************/ + +let reverseMode = false; + +/******************************************************************************/ + +function disableToolbarIcon(tabId) { + const details = { + path: { + '16': '/img/icon_16_off.png', + '32': '/img/icon_32_off.png', + '64': '/img/icon_64_off.png', + '128': '/img/icon_128_off.png', + } + }; + if ( tabId !== undefined ) { + details.tabId = tabId; + } + browser.action.setIcon(details); +} + +function enableToolbarIcon(tabId) { + const details = { + path: { + '16': '/img/icon_16.png', + '32': '/img/icon_32.png', + '64': '/img/icon_64.png', + '128': '/img/icon_128.png', + } + }; + if ( tabId !== undefined ) { + details.tabId = tabId; + } + browser.action.setIcon(details); +} + +/******************************************************************************/ + +export function toggleToolbarIcon(tabId) { + if ( reverseMode ) { + enableToolbarIcon(tabId); + } else { + disableToolbarIcon(tabId); + } +} + +/******************************************************************************/ + +// https://github.com/uBlockOrigin/uBOL-home/issues/198 +// Ensure the toolbar icon reflects the no-filtering mode of "trusted sites" + +export async function registerToolbarIconToggler(context) { + const { none, basic, optimal, complete } = context.filteringModeDetails; + const reverseModeAfter = none.delete('all-urls'); + const toToggle = reverseModeAfter ? + new Set([ ...basic, ...optimal, ...complete ]) + : none; + + if ( reverseModeAfter !== reverseMode ) { + if ( reverseModeAfter ) { + disableToolbarIcon(); + } else { + enableToolbarIcon(); + } + reverseMode = reverseModeAfter; + } + + if ( toToggle.size === 0 ) { return; } + + const registered = context.before.get('toolbar-icon'); + context.before.delete('toolbar-icon'); // Important! + + const directive = { + id: 'toolbar-icon', + js: [ '/js/scripting/toolbar-icon.js' ], + matches: matchesFromHostnames(toToggle), + runAt: 'document_start', + }; + + if ( registered === undefined ) { + context.toAdd.push(directive); + } else if ( strArrayEq(registered.matches, directive.matches) === false ) { + context.toRemove.push('toolbar-icon'); + context.toAdd.push(directive); + } +} diff --git a/platform/mv3/extension/js/admin.js b/platform/mv3/extension/js/admin.js new file mode 100644 index 0000000000000..1df2c5079e89c --- /dev/null +++ b/platform/mv3/extension/js/admin.js @@ -0,0 +1,215 @@ +/******************************************************************************* + + 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, localRemove, localWrite, + sessionRead, sessionWrite, +} from './ext.js'; + +import { + enableRulesets, + getRulesetDetails, + setStrictBlockMode, +} from './ruleset-manager.js'; + +import { + getDefaultFilteringMode, + readFilteringModeDetails, +} from './mode-manager.js'; + +import { + rulesetConfig, + saveRulesetConfig, +} from './config.js'; + +import { broadcastMessage } from './utils.js'; +import { dnr } from './ext-compat.js'; +import { registerInjectables } from './scripting-manager.js'; +import { ubolLog } from './debug.js'; + +/******************************************************************************/ + +export async function loadAdminConfig() { + const [ + showBlockedCount, + strictBlockMode, + ] = await Promise.all([ + adminReadEx('showBlockedCount'), + adminReadEx('strictBlockMode'), + ]); + applyAdminConfig({ showBlockedCount, strictBlockMode }); +} + +/******************************************************************************/ + +function applyAdminConfig(config, apply = false) { + const toApply = []; + for ( const [ key, val ] of Object.entries(config) ) { + if ( typeof val !== typeof rulesetConfig[key] ) { continue; } + if ( val === rulesetConfig[key] ) { continue; } + rulesetConfig[key] = val; + toApply.push(key); + } + if ( toApply.length === 0 ) { return; } + saveRulesetConfig(); + if ( apply !== true ) { return; } + while ( toApply.length !== 0 ) { + const key = toApply.pop(); + switch ( key ) { + case 'showBlockedCount': { + if ( typeof dnr.setExtensionActionOptions !== 'function' ) { break; } + const { showBlockedCount } = config; + dnr.setExtensionActionOptions({ + displayActionCountAsBadgeText: showBlockedCount, + }); + broadcastMessage({ showBlockedCount }); + break; + } + case 'strictBlockMode': { + const { strictBlockMode } = config; + setStrictBlockMode(strictBlockMode, true).then(( ) => { + broadcastMessage({ strictBlockMode }); + }); + break; + } + default: + break; + } + } +} + +/******************************************************************************/ + +const adminSettings = { + keys: new Map(), + timer: undefined, + change(key, value) { + this.keys.set(key, value); + 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('defaultFiltering') ) { + ubolLog('admin setting "defaultFiltering" changed'); + await readFilteringModeDetails(true); + await registerInjectables(); + const defaultFilteringMode = await getDefaultFilteringMode(); + broadcastMessage({ defaultFilteringMode }); + } + if ( this.keys.has('noFiltering') ) { + ubolLog('admin setting "noFiltering" changed'); + const filteringModeDetails = await readFilteringModeDetails(true); + broadcastMessage({ filteringModeDetails }); + } + if ( this.keys.has('showBlockedCount') ) { + ubolLog('admin setting "showBlockedCount" changed'); + const showBlockedCount = this.keys.get('showBlockedCount'); + applyAdminConfig({ showBlockedCount }, true); + } + if ( this.keys.has('strictBlockMode') ) { + ubolLog('admin setting "strictBlockMode" changed'); + const strictBlockMode = this.keys.get('strictBlockMode'); + applyAdminConfig({ strictBlockMode }, true); + } + this.keys.clear(); + } +}; + +/******************************************************************************/ + +export async function getAdminRulesets() { + const [ + adminList, + rulesetDetails, + ] = await Promise.all([ + adminReadEx('rulesets'), + getRulesetDetails(), + ]); + const adminRulesets = new Set(Array.isArray(adminList) && adminList || []); + if ( adminRulesets.has('-default') ) { + adminRulesets.delete('-default'); + for ( const ruleset of rulesetDetails.values() ) { + if ( ruleset.enabled !== true ) { continue; } + if ( adminRulesets.has(`+${ruleset.id}`) ) { continue; } + adminRulesets.add(`-${ruleset.id}`); + } + } + if ( adminRulesets.has('+default') ) { + adminRulesets.delete('+default'); + for ( const ruleset of rulesetDetails.values() ) { + if ( ruleset.enabled !== true ) { continue; } + if ( adminRulesets.has(`-${ruleset.id}`) ) { continue; } + adminRulesets.add(`+${ruleset.id}`); + } + } + if ( adminRulesets.has('-*') ) { + adminRulesets.delete('-*'); + 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; + } + localRemove(`admin_${key}`); // TODO: remove eventually + } + 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, value); + }); + return cacheValue; +} + +/******************************************************************************/ diff --git a/platform/mv3/extension/js/background.js b/platform/mv3/extension/js/background.js index e65775e9db7f8..7b46f8914e723 100644 --- a/platform/mv3/extension/js/background.js +++ b/platform/mv3/extension/js/background.js @@ -19,59 +19,85 @@ Home: https://github.com/gorhill/uBlock */ -/******************************************************************************/ +import { + MODE_BASIC, + MODE_OPTIMAL, + getDefaultFilteringMode, + getFilteringMode, + getFilteringModeDetails, + setDefaultFilteringMode, + setFilteringMode, + setFilteringModeDetails, + syncWithBrowserPermissions, +} from './mode-manager.js'; import { - adminRead, - browser, - dnr, - localRead, localWrite, - runtime, - sessionRead, sessionWrite, -} from './ext.js'; + addCustomFilter, + hasCustomFilters, + injectCustomFilters, + removeCustomFilter, + selectorsFromCustomFilters, + uninjectCustomFilters, +} from './filter-manager.js'; + +import { + adminReadEx, + getAdminRulesets, + loadAdminConfig, +} from './admin.js'; import { broadcastMessage, - ubolLog, + gotoURL, + hasBroadHostPermissions, + hostnamesFromMatches, } from './utils.js'; import { - defaultRulesetsFromLanguage, + browser, + localRead, localRemove, localWrite, + runtime, +} from './ext.js'; + +import { enableRulesets, - getEnabledRulesetsDetails, + excludeFromStrictBlock, + getEffectiveDynamicRules, + getEffectiveSessionRules, + getEffectiveUserRules, getRulesetDetails, + patchDefaultRulesets, + setStrictBlockMode, updateDynamicRules, + updateSessionRules, + updateUserRules, } 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 { dnr } from './ext-compat.js'; +import { registerInjectables } from './scripting-manager.js'; +import { toggleToolbarIcon } from './action.js'; -const rulesetConfig = { - version: '', - enabledRulesets: [ 'default' ], - autoReload: true, - showBlockedCount: true, -}; +/******************************************************************************/ -const UBOL_ORIGIN = runtime.getURL('').replace(/\/$/, ''); +const UBOL_ORIGIN = runtime.getURL('').replace(/\/$/, '').toLowerCase(); const canShowBlockedCount = typeof dnr.setExtensionActionOptions === 'function'; -let firstRun = false; -let wakeupRun = false; +let pendingPermissionRequest; /******************************************************************************/ @@ -79,83 +105,71 @@ 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) { - if ( /^https?:\/\//.test(origin) === false ) { return false; } - return browser.permissions.contains({ - origins: [ `${origin}/*` ], - }); -} - -function hasOmnipotence() { - return browser.permissions.contains({ - origins: [ '' ], - }); -} - async function onPermissionsRemoved() { - const beforeMode = await getDefaultFilteringMode(); const modified = await syncWithBrowserPermissions(); if ( modified === false ) { return false; } - const afterMode = await getDefaultFilteringMode(); - if ( beforeMode > 1 && afterMode <= 1 ) { - updateDynamicRules(); - } registerInjectables(); return true; } +// https://github.com/uBlockOrigin/uBOL-home/issues/280 +async function onPermissionsAdded(permissions) { + const details = pendingPermissionRequest; + pendingPermissionRequest = undefined; + if ( details === undefined ) { + const modified = await syncWithBrowserPermissions(); + if ( modified === false ) { return; } + return Promise.all([ + updateSessionRules(), + registerInjectables(), + ]); + } + const defaultMode = await getDefaultFilteringMode(); + if ( defaultMode >= MODE_OPTIMAL ) { return; } + if ( Array.isArray(permissions.origins) === false ) { return; } + const hostnames = hostnamesFromMatches(permissions.origins); + if ( hostnames.includes(details.hostname) === false ) { return; } + const beforeLevel = await getFilteringMode(details.hostname); + if ( beforeLevel === details.afterLevel ) { return; } + const afterLevel = await setFilteringMode(details.hostname, details.afterLevel); + if ( afterLevel !== details.afterLevel ) { return; } + await registerInjectables(); + if ( rulesetConfig.autoReload ) { + self.setTimeout(( ) => { + browser.tabs.update(details.tabId, { + url: details.url, + }); + }, 437); + } +} + +/******************************************************************************/ + +function setDeveloperMode(state) { + rulesetConfig.developerMode = state === true; + toggleDeveloperMode(rulesetConfig.developerMode); + broadcastMessage({ developerMode: rulesetConfig.developerMode }); + return Promise.all([ + updateUserRules(), + saveRulesetConfig(), + ]); +} + /******************************************************************************/ function onMessage(request, sender, callback) { + const tabId = sender?.tab?.id ?? false; + const frameId = tabId && (sender?.frameId ?? false); + // Does not require trusted origin. switch ( request.what ) { case 'insertCSS': { - const tabId = sender?.tab?.id ?? false; - const frameId = sender?.frameId ?? false; - if ( tabId === false || frameId === false ) { return; } + if ( frameId === false ) { return false; } browser.scripting.insertCSS({ css: request.css, origin: 'USER', @@ -166,6 +180,50 @@ function onMessage(request, sender, callback) { return false; } + case 'removeCSS': { + if ( frameId === false ) { return false; } + browser.scripting.removeCSS({ + css: request.css, + origin: 'USER', + target: { tabId, frameIds: [ frameId ] }, + }).catch(reason => { + console.log(reason); + }); + return false; + } + + case 'toggleToolbarIcon': { + if ( tabId ) { + toggleToolbarIcon(tabId); + } + return false; + } + + case 'injectCustomFilters': + if ( frameId === false ) { return false; } + injectCustomFilters(tabId, frameId, request.hostname).then(selectors => { + callback(selectors); + }); + return true; + + case 'uninjectCustomFilters': + if ( frameId === false ) { return false; } + uninjectCustomFilters(tabId, frameId, request.hostname).then(( ) => { + callback(); + }); + return true; + + case 'injectCSSProceduralAPI': + browser.scripting.executeScript({ + files: [ '/js/scripting/css-procedural-api.js' ], + target: { tabId, frameIds: [ frameId ] }, + }).catch(reason => { + console.log(reason); + }).then(( ) => { + callback(); + }); + return true; + default: break; } @@ -174,7 +232,9 @@ function onMessage(request, sender, callback) { // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/MessageSender // Firefox API does not set `sender.origin` - if ( sender.origin !== undefined && sender.origin !== UBOL_ORIGIN ) { return; } + if ( sender.origin !== undefined ) { + if ( sender.origin.toLowerCase() !== UBOL_ORIGIN ) { return; } + } switch ( request.what ) { @@ -185,39 +245,55 @@ function onMessage(request, sender, callback) { }).then(( ) => { registerInjectables(); callback(); - broadcastMessage({ enabledRulesets: rulesetConfig.enabledRulesets }); + return dnr.getEnabledRulesets(); + }).then(enabledRulesets => { + broadcastMessage({ enabledRulesets }); }); return true; } - case 'getOptionsPageData': { + case 'getOptionsPageData': Promise.all([ + hasBroadHostPermissions(), getDefaultFilteringMode(), - getTrustedSites(), getRulesetDetails(), dnr.getEnabledRulesets(), + getAdminRulesets(), + adminReadEx('disabledFeatures'), ]).then(results => { const [ + hasOmnipotence, defaultFilteringMode, - trustedSites, rulesetDetails, enabledRulesets, + adminRulesets, + disabledFeatures, ] = results; callback({ + hasOmnipotence, defaultFilteringMode, - trustedSites: Array.from(trustedSites), enabledRulesets, + adminRulesets, maxNumberOfEnabledRulesets: dnr.MAX_NUMBER_OF_ENABLED_STATIC_RULESETS, 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; + + case 'getRulesetDetails': + getRulesetDetails().then(rulesetDetails => { + callback(Array.from(rulesetDetails.values())); }); return true; - } case 'setAutoReload': rulesetConfig.autoReload = request.state && true || false; @@ -240,19 +316,34 @@ function onMessage(request, sender, callback) { }); return true; + case 'setStrictBlockMode': + setStrictBlockMode(request.state).then(( ) => { + callback(); + broadcastMessage({ strictBlockMode: rulesetConfig.strictBlockMode }); + }); + return true; + + case 'setDeveloperMode': + setDeveloperMode(request.state).then(( ) => { + callback(); + }); + return true; + case 'popupPanelData': { Promise.all([ - getFilteringMode(request.hostname), - hasOmnipotence(), - hasGreatPowers(request.origin), - getEnabledRulesetsDetails(), + hasBroadHostPermissions(), + getFilteringMode(request.normalHostname), + adminReadEx('disabledFeatures'), + hasCustomFilters(request.hostname), ]).then(results => { callback({ - level: results[0], + hasOmnipotence: results[0], + level: results[1], autoReload: rulesetConfig.autoReload, - hasOmnipotence: results[1], - hasGreatPowers: results[2], - rulesetDetails: results[3], + isSideloaded, + developerMode: rulesetConfig.developerMode, + disabledFeatures: results[2], + hasCustomFilters: results[3], }); }); return true; @@ -265,116 +356,289 @@ 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; } + getFilteringMode(request.hostname).then(beforeLevel => { + if ( request.level === beforeLevel ) { return beforeLevel; } return setFilteringMode(request.hostname, request.level); - }).then(actualLevel => { + }).then(afterLevel => { registerInjectables(); - callback(actualLevel); + callback(afterLevel); + }); + return true; + } + + case 'setPendingFilteringMode': + pendingPermissionRequest = request; + break; + + case 'getDefaultFilteringMode': { + getDefaultFilteringMode().then(level => { + callback(level); }); return true; } - case 'setDefaultFilteringMode': { + case 'setDefaultFilteringMode': getDefaultFilteringMode().then(beforeLevel => setDefaultFilteringMode(request.level).then(afterLevel => ({ beforeLevel, afterLevel }) ) ).then(({ beforeLevel, afterLevel }) => { - if ( beforeLevel === 1 || afterLevel === 1 ) { - updateDynamicRules(); - } if ( afterLevel !== beforeLevel ) { registerInjectables(); } callback(afterLevel); }); return true; - } - case 'setTrustedSites': - setTrustedSites(request.hostnames).then(( ) => { + case 'getFilteringModeDetails': + getFilteringModeDetails(true).then(details => { + callback(details); + }); + return true; + + case 'setFilteringModeDetails': + setFilteringModeDetails(request.modes).then(( ) => { registerInjectables(); - return Promise.all([ - getDefaultFilteringMode(), - getTrustedSites(), - ]); - }).then(results => { - callback({ - defaultFilteringMode: results[0], - trustedSites: Array.from(results[1]), + getDefaultFilteringMode().then(defaultFilteringMode => { + broadcastMessage({ defaultFilteringMode }); }); + getFilteringModeDetails(true).then(details => { + callback(details); + }); + }); + return true; + + case 'excludeFromStrictBlock': { + excludeFromStrictBlock(request.hostname, request.permanent).then(( ) => { + callback(); + }); + return true; + } + + case 'getMatchedRules': + getMatchedRules(request.tabId).then(entries => { + callback(entries); + }); + return true; + + case 'showMatchedRules': + browser.windows.create({ + type: 'popup', + url: `/matched-rules.html?tab=${request.tabId}`, + }); + break; + + case 'getEffectiveDynamicRules': + getEffectiveDynamicRules().then(result => { + callback(result); + }); + return true; + + case 'getEffectiveSessionRules': + getEffectiveSessionRules().then(result => { + callback(result); + }); + return true; + + case 'getEffectiveUserRules': + getEffectiveUserRules().then(result => { + callback(result); + }); + return true; + + case 'updateUserDnrRules': + updateUserRules().then(result => { + callback(result); + }); + return true; + + case 'addCustomFilter': + addCustomFilter(request.hostname, request.selector).then(modified => { + if ( modified !== true ) { return; } + return registerInjectables(); + }).then(( ) => { + callback(); + }) + return true; + + case 'removeCustomFilter': + removeCustomFilter(request.hostname, request.selector).then(modified => { + if ( modified !== true ) { return; } + return registerInjectables(); + }).then(( ) => { + callback(); + }); + return true; + + case 'selectorsFromCustomFilters': + selectorsFromCustomFilters(request.hostname).then(selectors => { + callback(selectors); }); return true; default: break; } + + return false; } /******************************************************************************/ -async function start() { - await loadRulesetConfig(); +function onCommand(command, tab) { + switch ( command ) { + case 'enter-zapper-mode': { + if ( browser.scripting === undefined ) { return; } + browser.scripting.executeScript({ + files: [ '/js/scripting/tool-overlay.js', '/js/scripting/zapper.js' ], + target: { tabId: tab.id }, + }); + break; + } + case 'enter-picker-mode': { + if ( browser.scripting === undefined ) { return; } + browser.scripting.executeScript({ + files: [ '/js/scripting/tool-overlay.js', '/js/scripting/picker.js' ], + target: { tabId: tab.id }, + }); + break; + } + default: + break; + } +} + +/******************************************************************************/ + +async function startSession() { + const currentVersion = getCurrentVersion(); + const isNewVersion = currentVersion !== rulesetConfig.version; + + // Admin settings override user settings + await loadAdminConfig(); - if ( wakeupRun === false ) { - await enableRulesets(rulesetConfig.enabledRulesets); + // 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 = 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 ( rulesetsUpdated === false ) { + if ( isNewVersion ) { + updateDynamicRules(); + } else { + updateSessionRules(); } } // Permissions may have been removed while the extension was disabled - const permissionsChanged = await onPermissionsRemoved(); + await syncWithBrowserPermissions(); // Unsure whether the browser remembers correctly registered css/scripts // after we quit the browser. For now uBOL will check unconditionally at // launch time whether content css/scripts are properly registered. - if ( wakeupRun === false || permissionsChanged ) { - registerInjectables(); - - const enabledRulesets = await dnr.getEnabledRulesets(); - ubolLog(`Enabled rulesets: ${enabledRulesets}`); - - dnr.getAvailableStaticRuleCount().then(count => { - ubolLog(`Available static rule count: ${count}`); - }); - } + registerInjectables(); // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/declarativeNetRequest // Firefox API does not support `dnr.setExtensionActionOptions` - if ( wakeupRun === false && canShowBlockedCount ) { + if ( canShowBlockedCount ) { dnr.setExtensionActionOptions({ displayActionCountAsBadgeText: rulesetConfig.showBlockedCount, }); } - runtime.onMessage.addListener(onMessage); - - browser.permissions.onRemoved.addListener( - ( ) => { onPermissionsRemoved(); } - ); + // Switch to basic filtering if uBOL doesn't have broad permissions at + // install time. + if ( process.firstRun ) { + const enableOptimal = await hasBroadHostPermissions(); + if ( enableOptimal === false ) { + const afterLevel = await setDefaultFilteringMode(MODE_BASIC); + if ( afterLevel === MODE_BASIC ) { + registerInjectables(); + process.firstRun = false; + } + } + } - if ( firstRun ) { - const disableFirstRunPage = await adminRead('disableFirstRunPage'); - if ( disableFirstRunPage !== true ) { - runtime.openOptionsPage(); + // Required to ensure up to date properties are available when needed + adminReadEx('disabledFeatures').then(items => { + if ( Array.isArray(items) === false ) { return; } + if ( items.includes('develop') ) { + if ( rulesetConfig.developerMode ) { + setDeveloperMode(false); + } } + }); +} + +/******************************************************************************/ + +async function start() { + await loadRulesetConfig(); + + if ( process.wakeupRun === false ) { + await startSession(); } + + toggleDeveloperMode(rulesetConfig.developerMode); } -try { - start(); -} catch(reason) { +/******************************************************************************/ + +// https://github.com/uBlockOrigin/uBOL-home/issues/199 +// Force a restart of the extension once when an "internal error" occurs + +const isFullyInitialized = 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(); +}); + +runtime.onMessage.addListener((request, sender, callback) => { + isFullyInitialized.then(( ) => { + const r = onMessage(request, sender, callback); + if ( r !== true ) { callback(); } + }); + return true; +}); + +browser.permissions.onRemoved.addListener((...args) => { + isFullyInitialized.then(( ) => { + onPermissionsRemoved(...args); + }); +}); + +browser.permissions.onAdded.addListener((...args) => { + isFullyInitialized.then(( ) => { + onPermissionsAdded(...args); + }); +}); + +browser.commands.onCommand.addListener((...args) => { + isFullyInitialized.then(( ) => { + onCommand(...args); + }); +}); diff --git a/platform/mv3/extension/js/config.js b/platform/mv3/extension/js/config.js new file mode 100644 index 0000000000000..f48533473f189 --- /dev/null +++ b/platform/mv3/extension/js/config.js @@ -0,0 +1,67 @@ +/******************************************************************************* + + 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, + hasBroadHostPermissions: true, +}; + +export const process = { + firstRun: false, + wakeupRun: false, +}; + +/******************************************************************************/ + +export async function loadRulesetConfig() { + const sessionData = await sessionRead('rulesetConfig'); + if ( sessionData ) { + Object.assign(rulesetConfig, sessionData); + process.wakeupRun = true; + return; + } + const localData = await localRead('rulesetConfig'); + if ( localData ) { + Object.assign(rulesetConfig, localData) + 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..113d7481f50e5 100644 --- a/platform/mv3/extension/js/dashboard.js +++ b/platform/mv3/extension/js/dashboard.js @@ -19,10 +19,15 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; +import { dom, qs$ } from './dom.js'; +import { + localRead, + localRemove, + localWrite, +} from './ext.js'; +import { getTroubleshootingInfo } from './troubleshooting.js'; import { runtime } from './ext.js'; -import { dom } from './dom.js'; /******************************************************************************/ @@ -34,7 +39,28 @@ import { dom } from './dom.js'; dom.attr('a', 'target', '_blank'); dom.on('#dashboard-nav', 'click', '.tabButton', ev => { - dom.body.dataset.pane = ev.target.dataset.pane; + const { pane } = ev.target.dataset; + dom.body.dataset.pane = pane; + if ( pane === 'settings' ) { + localRemove('dashboard.activePane'); + } else { + localWrite('dashboard.activePane', pane); + } }); +localRead('dashboard.activePane').then(pane => { + if ( typeof pane !== 'string' ) { return; } + dom.body.dataset.pane = pane; +}); + +getTroubleshootingInfo().then(config => { + qs$('[data-i18n="supportS5H"] + pre').textContent = config; +}); + +/******************************************************************************/ + +export function hashFromIterable(iter) { + return Array.from(iter).sort().join('\n'); +} + /******************************************************************************/ diff --git a/platform/mv3/extension/js/debug.js b/platform/mv3/extension/js/debug.js new file mode 100644 index 0000000000000..e5778132742f5 --- /dev/null +++ b/platform/mv3/extension/js/debug.js @@ -0,0 +1,152 @@ +/******************************************************************************* + + 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, normalizeDNRRules } from './ext-compat.js'; +import { browser } from './ext.js'; + +/******************************************************************************/ + +const isModern = dnr.onRuleMatchedDebug instanceof Object; + +export const isSideloaded = (( ) => { + const { permissions } = browser.runtime.getManifest(); + return permissions?.includes('declarativeNetRequestFeedback') ?? false; +})(); + +/******************************************************************************/ + +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 <= 11 ) { return list; } + return [ ...list.slice(0, 5), '...', ...list.slice(-5) ]; +}; + +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 + ).then(rules => + normalizeDNRRules(rules) + ); + } + 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 = (( ) => { + if ( isSideloaded !== true ) { + return ( ) => Promise.resolve([]); + } + + if ( isModern ) { + return async tabId => { + const promises = []; + for ( let i = 0; i < bufferSize; i++ ) { + const j = (writePtr + i) % bufferSize; + const ruleInfo = matchedRules[j]; + if ( ruleInfo === null ) { continue; } + if ( ruleInfo.request.tabId !== -1 ) { + if ( ruleInfo.request.tabId !== tabId ) { continue; } + } + const promise = getRuleDetails(ruleInfo); + if ( promise === undefined ) { continue; } + promises.unshift(promise); + } + return Promise.all(promises); + }; + } + + return async tabId => { + if ( typeof dnr.getMatchedRules !== 'function' ) { return []; } + const matchedRules = await dnr.getMatchedRules({ tabId }); + if ( matchedRules instanceof Object === false ) { return []; } + const promises = []; + for ( const { tabId, rule } of matchedRules.rulesMatchedInfo ) { + promises.push(getRuleDetails({ request: { tabId }, rule })); + } + return Promise.all(promises); + }; +})(); + +/******************************************************************************/ + +const matchedRuleListener = ruleInfo => { + matchedRules[writePtr] = ruleInfo; + writePtr = (writePtr + 1) % bufferSize; +}; + +export const toggleDeveloperMode = state => { + if ( isSideloaded !== true ) { return; } + if ( isModern === false ) { return; } + if ( state ) { + dnr.onRuleMatchedDebug.addListener(matchedRuleListener); + } else { + dnr.onRuleMatchedDebug.removeListener(matchedRuleListener); + } +}; + +/******************************************************************************/ diff --git a/platform/mv3/extension/js/develop.js b/platform/mv3/extension/js/develop.js new file mode 100644 index 0000000000000..0413c708fcaa4 --- /dev/null +++ b/platform/mv3/extension/js/develop.js @@ -0,0 +1,633 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2014-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { dom, qs$, qsa$ } from './dom.js'; +import { localRead, localWrite, sendMessage } from './ext.js'; +import { faIconsInit } from './fa-icons.js'; +import { i18n } from './i18n.js'; + +/******************************************************************************/ + +class Editor { + constructor() { + this.lastSavedText = ''; + this.view = null; + this.reYamlDocSeparator = /^(?:---|...)\s*$/; + this.modifiedRange = { start: 0, end: 0 }; + this.updateTimer = undefined; + this.ioPanel = self.cm6.createViewPanel(); + this.summaryPanel = self.cm6.createViewPanel(); + this.panels = []; + this.editors = {}; + } + + async init() { + await Promise.all([ + import('./mode-editor.js').then(module => { + this.editors['modes'] = new module.ModeEditor(this); + }), + import('./ro-dnr-editor.js').then(module => { + this.editors['dnr.ro'] = new module.ReadOnlyDNREditor(this); + }), + import('./rw-dnr-editor.js').then(module => { + this.editors['dnr.rw'] = new module.ReadWriteDNREditor(this); + }), + ]); + const rulesetDetails = await sendMessage({ what: 'getRulesetDetails' }); + const parent = qs$('#editors optgroup'); + for ( const details of rulesetDetails ) { + const option = document.createElement('option'); + option.value = `dnr.ro.${details.id}`; + option.textContent = details.name; + parent.append(option); + } + this.validModes = Array.from(qsa$('#editors option')).map(a => a.value); + const mode = await localRead('dashboard.develop.editor'); + this.editorFromMode(mode); + const text = this.normalizeEditorText(await this.editor.getText(this.mode)); + const viewConfig = { + text, + yamlLike: true, + oneDark: dom.cl.has(':root', 'dark'), + updateListener: info => { this.viewUpdateListener(info); }, + saveListener: ( ) => { this.saveEditorText(); }, + lineError: true, + spanError: true, + // https://codemirror.net/examples/autocompletion/ + autocompletion: { + override: [ + context => { + return this.autoComplete(context); + }, + ], + activateOnCompletion: ( ) => true, + }, + gutterClick: (view, info) => { + return this.gutterClick(view, info); + }, + hoverTooltip: (view, pos, side) => { + return this.hoverTooltip(view, pos, side); + }, + streamParser: this.streamParser, + foldService: (state, from) => { + return this.foldService(state, from); + }, + readOnly: this.isReadOnly(), + }; + viewConfig.panels = [ this.ioPanel, this.summaryPanel, ...this.panels ]; + this.view = self.cm6.createEditorView(viewConfig, qs$('#cm-container')); + this.lastSavedText = text; + self.cm6.foldAll(this.view); + self.cm6.resetUndoRedo(this.view); + this.updateIOPanel(); + this.editor.on?.(this); + this.modifiedRange.start = 1; + this.modifiedRange.end = this.view.state.doc.lines; + this.updateViewAsync(); + } + + normalizeEditorText(text) { + text ||= ''; + text = text.trim(); + if ( text !== '' ) { text += '\n'; } + return text; + } + + setEditorText(text, saved = false) { + text = this.normalizeEditorText(text); + if ( saved ) { + this.lastSavedText = text; + } + this.view.dispatch({ + changes: { + from: 0, to: this.view.state.doc.length, + insert: text, + }, + }); + this.view.focus(); + } + + getEditorText() { + return this.view.state.doc.toString(); + } + + editorTextChanged() { + const text = this.normalizeEditorText(this.getEditorText()); + return text !== this.lastSavedText; + } + + async selectEditor(mode) { + if ( mode === this.mode ) { return; } + this.editorFromMode(mode); + const text = await this.editor.getText(this.mode); + this.setEditorText(text); + this.lastSavedText = this.getEditorText(); + self.cm6.foldAll(this.view) + self.cm6.resetUndoRedo(this.view); + self.cm6.toggleReadOnly(this.view, this.isReadOnly()); + this.updateIOPanel(); + this.editor.on?.(this); + this.modifiedRange.start = 1; + this.modifiedRange.end = this.view.state.doc.lines; + this.updateViewAsync(); + } + + editorFromMode(mode) { + if ( this.validModes.includes(mode) === false ) { + mode = 'modes'; + } + if ( mode === this.mode ) { return mode; } + let editor; + if ( mode === 'modes' ) { + editor = this.editors['modes']; + } else if ( mode.startsWith('dnr.rw.') ) { + editor = this.editors['dnr.rw']; + } else if ( mode.startsWith('dnr.ro.') ) { + editor = this.editors['dnr.ro']; + } else { + return; + } + this.editor?.off?.(this); + this.editor = editor; + this.mode = mode; + const select = qs$('#editors'); + select.value = mode; + } + + isReadOnly() { + return typeof this.editor.saveEditorText !== 'function'; + } + + viewUpdateListener(info) { + if ( info.docChanged === false ) { return; } + for ( const transaction of info.transactions ) { + if ( transaction.docChanged === false ) { continue; } + this.addToModifiedRange(transaction); + if ( transaction.isUserEvent('delete.backward') ) { + this.smartBackspace(transaction); + } else if ( transaction.isUserEvent('input.paste') ) { + if ( this.editor.importFromPaste ) { + this.editor.importFromPaste(this, transaction); + } + } else if ( transaction.isUserEvent('input') ) { + if ( this.smartReturn(transaction) ) { continue; } + this.smartSpacebar(transaction); + } + } + this.updateViewAsync(); + } + + updateViewAsync() { + if ( this.updateTimer !== undefined ) { return; } + this.updateTimer = self.setTimeout(( ) => { + this.updateTimer = undefined; + this.updateView(); + }, 71); + } + + updateView() { + const { doc } = this.view.state; + const changed = this.editorTextChanged(); + dom.attr('#apply', 'disabled', changed ? null : ''); + dom.attr('#revert', 'disabled', changed ? null : ''); + if ( typeof this.editor.updateView !== 'function' ) { return; } + let { start, end } = this.modifiedRange; + if ( start === 0 || end === 0 ) { return; } + this.modifiedRange.start = this.modifiedRange.end = 0; + if ( start > doc.lines ) { start = doc.lines; } + if ( end > doc.lines ) { end = doc.lines; } + self.cm6.lineErrorClear(this.view, start, end); + self.cm6.spanErrorClear(this.view, start, end); + const firstLine = doc.line(start); + const lastLine = doc.line(end); + this.editor.updateView(this, firstLine, lastLine); + } + + updateIOPanel() { + const ioButtons = []; + if ( this.editor.saveEditorText ) { + ioButtons.push('apply', 'revert'); + } + if ( this.editor.importFromFile ) { + ioButtons.push('import'); + } + if ( this.editor.exportToFile ) { + ioButtons.push('export'); + } + if ( ioButtons.length === 0 ) { + return this.ioPanel.render(this.view, null); + } + const template = document.querySelector('template.io-panel'); + const fragment = template.content.cloneNode(true); + const root = fragment.querySelector('.io-panel'); + i18n.render(root); + faIconsInit(root); + root.dataset.io = ioButtons.join(' '); + const config = { + dom: root, + mount: ( ) => { + dom.on('#apply', 'click', ( ) => { + this.saveEditorText(); + }); + dom.on('#revert', 'click', ( ) => { + this.revertEditorText(); + }); + dom.on('#import', 'click', ( ) => { + this.importFromFile() + }); + dom.on('#export', 'click', ( ) => { + this.exportToFile(); + }); + } + }; + this.ioPanel.render(this.view, config); + } + + updateSummaryPanel(dom) { + if ( dom instanceof Object ) { + if ( this.updateSummaryPanel.timer !== undefined ) { + self.clearTimeout(this.updateSummaryPanel.timer); + this.updateSummaryPanel.timer = undefined; + } + return this.summaryPanel.render(this.view, { dom }); + } + if ( this.updateSummaryPanel.timer !== undefined ) { return; } + this.updateSummaryPanel.timer = self.setTimeout(( ) => { + this.updateSummaryPanel.timer = undefined; + this.summaryPanel.render(this.view, null); + }, 157); + } + + autoComplete(context) { + if ( typeof this.editor.autoComplete !== 'function' ) { return null; } + return this.editor.autoComplete(this, context); + } + + hoverTooltip(view, pos, side) { + if ( typeof this.editor.createTooltipWidget !== 'function' ) { return null; } + const details = view.domAtPos(pos); + const textNode = details.node; + if ( textNode.nodeType !== 3 ) { return null; } + const { parentElement } = textNode; + const targetElement = parentElement.closest('[data-tooltip]'); + if ( targetElement === null ) { return null; } + const tooltipText = targetElement.getAttribute('data-tooltip'); + if ( Boolean(tooltipText) === false ) { return null; } + const start = pos - details.offset; + const end = start + textNode.nodeValue.length; + if ( start === pos && side < 0 || end === pos && side > 0 ) { return null; } + return { + above: true, + pos: start, + end, + create: ( ) => { + return { dom: this.editor.createTooltipWidget(tooltipText) }; + }, + }; + } + + foldService(state, from) { + if ( typeof this.editor.foldService !== 'function' ) { return null; } + return this.editor.foldService(state, from); + } + + // Details of YAML document(s) intersecting with a text span. If the text span + // starts on a YAML document divider, the previous YAML document will be + // included. If the text span ends on a YAML document divider, the next YAML + // document will be included. + + snapToYamlDocument(doc, start, end) { + let yamlDocStart = doc.lineAt(start).number; + if ( this.reYamlDocSeparator.test(doc.line(yamlDocStart).text) ) { + if ( yamlDocStart > 1 ) { + yamlDocStart -= 1; + } + } + while ( yamlDocStart > 1 ) { + const line = doc.line(yamlDocStart); + if ( this.reYamlDocSeparator.test(line.text) ) { break; } + yamlDocStart -= 1; + } + const lastLine = doc.lines; + let yamlDocEnd = doc.lineAt(end).number; + if ( this.reYamlDocSeparator.test(doc.line(yamlDocEnd).text) ) { + if ( yamlDocEnd < lastLine ) { + yamlDocEnd += 1; + } + } + while ( yamlDocEnd < lastLine ) { + const line = doc.line(yamlDocEnd); + if ( this.reYamlDocSeparator.test(line.text) ) { break; } + yamlDocEnd += 1; + } + return { yamlDocStart, yamlDocEnd }; + } + + rangeFromTransaction(transaction) { + let from, to; + transaction.changes.iterChangedRanges((fromA, toA, fromB, toB) => { + if ( from === undefined || fromB < from ) { from = fromB; } + if ( to === undefined || toB > to ) { to = toB; } + }); + return { from, to }; + } + + addToModifiedRange(transaction) { + const { from, to } = this.rangeFromTransaction(transaction); + if ( from === undefined || to === undefined ) { return; } + const { newDoc } = transaction; + const { yamlDocStart, yamlDocEnd } = this.snapToYamlDocument(newDoc, from, to); + if ( this.modifiedRange.start === 0 || yamlDocStart < this.modifiedRange.start ) { + this.modifiedRange.start = yamlDocStart; + } + if ( this.modifiedRange.end === 0 || yamlDocEnd > this.modifiedRange.end ) { + this.modifiedRange.end = yamlDocEnd; + } + } + + lineIndentAt(line) { + const match = /^(?: {2})*/.exec(line.text); + const indent = match !== null ? match[0].length : -1; + if ( indent === -1 || (indent & 1) !== 0 ) { return -1; } + return indent / 2; + } + + getScopeAt(from, doc) { + doc ||= this.view.state.doc; + const lineFrom = doc.lineAt(from); + const out = {}; + let depth = this.lineIndentAt(lineFrom); + if ( depth === -1 ) { return out; } + const text = lineFrom.text.trim(); + if ( text.startsWith('#') ) { return out; } + const path = []; + const end = text.indexOf(':'); + if ( end !== -1 ) { + const beg = text.startsWith('- ') ? 2 : 0; + path.push(text.slice(beg, end+1)); + } + let lineNo = lineFrom.number; + while ( depth > 0 && lineNo > 1 ) { + lineNo -= 1; + const lineBefore = doc.line(lineNo); + const text = lineBefore.text.trim(); + if ( text.startsWith('#') ) { continue; } + if ( this.lineIndentAt(lineBefore) > (depth-1) ) { continue; } + const match = /^- ([^:]+:)/.exec(text); + if ( match !== null ) { + path.unshift(match[1]); + } else { + path.unshift(text); + } + depth -= 1; + } + out.scope = path.join(''); + out.depth = path.length; + return out; + } + + async saveEditorText() { + if ( typeof this.editor.saveEditorText !== 'function' ) { return; } + if ( this.editorTextChanged() === false ) { return; } + const saved = await this.editor.saveEditorText(this); + if ( saved !== true ) { return; } + this.lastSavedText = this.normalizeEditorText(this.getEditorText()); + this.updateView(); + } + + revertEditorText() { + if ( this.editorTextChanged() === false ) { return; } + this.setEditorText(this.lastSavedText); + } + + smartBackspace(transaction) { + const { from, to } = this.rangeFromTransaction(transaction); + if ( from === undefined || to === undefined ) { return; } + if ( to !== from ) { return; } + const { newDoc } = transaction; + const line = newDoc.lineAt(from); + if ( /^(?: {2})+-$/.test(line.text) === false ) { return; } + this.view.dispatch({ changes: { from: from-3, to: from, insert: '' } }); + return true; + } + + lineIsArrayItem(doc, lineNo) { + if ( lineNo < 1 || lineNo > doc.lines ) { return false; } + const line = doc.line(lineNo); + return /^(?: {2})+- /.test(line.text); + } + + smartArrayItem(doc, from) { + const line = doc.lineAt(from); + if ( line.from === 0 ) { return; } + const blanks = /^ *$/.exec(line.text); + if ( blanks === null ) { return; } + if ( this.editor.newlineAssistant ) { + const { scope } = this.getScopeAt(line.from-1, doc); + const insert = this.editor.newlineAssistant[scope]; + if ( insert ) { + this.view.dispatch({ + changes: { from: line.from, to: line.to, insert }, + selection: { anchor: line.from + insert.length }, + }); + return true; + } + } + let targetIndent; + if ( this.lineIsArrayItem(doc, line.number-1) ) { + targetIndent = doc.line(line.number-1).text.indexOf('- '); + } else if ( this.lineIsArrayItem(doc, line.number+1) ) { + targetIndent = doc.line(line.number+1).text.indexOf('- '); + } + if ( targetIndent === undefined ) { return; } + const indent = targetIndent - blanks[0].length; + if ( indent < 0 || indent > 2 ) { return; } + const insert = `${' '.repeat(indent)}- `; + this.view.dispatch({ + changes: { from, insert }, + selection: { anchor: from + insert.length }, + }); + return true; + } + + smartReturn(transaction) { + const { from, to } = this.rangeFromTransaction(transaction); + if ( from === undefined || to === undefined ) { return; } + const { newDoc } = transaction; + return this.smartArrayItem(newDoc, to); + } + + smartSpacebar(transaction) { + const { from, to } = this.rangeFromTransaction(transaction); + if ( from === undefined || to === undefined ) { return; } + if ( (to - from) !== 1 ) { return; } + const { newDoc } = transaction; + const line = newDoc.lineAt(to); + const localTo = to - line.from; + const before = line.text.slice(0, localTo); + if ( /^(?: {1}| {3})$/.test(before) === false ) { return; } + if ( this.smartArrayItem(newDoc, to) ) { return true; } + this.view.dispatch({ + changes: { from: to, insert: ' ' }, + selection: { anchor: to + 1 }, + }); + return true; + } + + gutterClick(view, info) { + const reSeparator = /^(?:---|# ---)\s*/; + const { doc } = view.state; + const lineFirst = doc.lineAt(info.from); + if ( lineFirst.text === '' ) { return false; } + let { from, to } = lineFirst; + if ( reSeparator.test(lineFirst.text) ) { + let lineNo = lineFirst.number + 1; + while ( lineNo < doc.lines ) { + const line = doc.line(lineNo); + if ( reSeparator.test(line.text) ) { break; } + to = line.to; + lineNo += 1; + } + } + view.dispatch({ + selection: { anchor: from, head: to+1 } + }); + view.focus(); + return true; + } + + importFromFile() { + const editor = this.editor; + if ( typeof editor.importFromFile !== 'function' ) { return; } + const input = qs$('input[type="file"]'); + input.accept = editor.ioAccept || ''; + input.onchange = ev => { + input.onchange = null; + const file = ev.target.files[0]; + if ( file === undefined || file.name === '' ) { return; } + const fr = new FileReader(); + fr.onload = ( ) => { + if ( typeof fr.result !== 'string' ) { return; } + editor.importFromFile(this, fr.result); + }; + fr.readAsText(file); + }; + // Reset to empty string, this will ensure a change event is properly + // triggered if the user pick a file, even if it's the same as the last + // one picked. + input.value = ''; + input.click(); + } + + exportToFile() { + const editor = this.editor; + if ( typeof editor.exportToFile !== 'function' ) { return; } + const text = this.getEditorText(); + const result = editor.exportToFile(text); + if ( result === undefined ) { return; } + const { fname, data, mime } = result; + const a = document.createElement('a'); + a.href = `data:${mime};charset=utf-8,${encodeURIComponent(data)}`; + dom.attr(a, 'download', fname || ''); + dom.attr(a, 'type', mime); + a.click(); + } + + streamParser = { + startState: ( ) => { + return { scope: 0 }; + }, + token: (stream, state) => { + if ( stream.sol() ) { + if ( stream.match(/^---\s*$/) ) { return 'ubol-boundary'; } + if ( stream.match(/^# ---\s*$/) ) { return 'ubol-boundary ubol-comment'; } + if ( stream.match(/\.\.\.\s*$/) ) { return 'ubol-boundary'; } + } + const c = stream.peek(); + if ( c === '#' ) { + if ( (stream.pos === 0 || /\s/.test(stream.string.charAt(stream.pos - 1))) ) { + stream.skipToEnd(); + return 'ubol-comment'; + } + } + if ( stream.eatSpace() ) { return null; } + const { scope } = state; + state.scope = 0; + if ( scope === 0 && stream.match(/^[^:]+(?=:)/) ) { + state.scope = 1; + return 'ubol-keyword'; + } + if ( scope === 1 && stream.match(/^:(?: |$)/) ) { + return 'ubol-punctuation'; + } + if ( stream.match(/^- /) ) { + return 'ubol-punctuation'; + } + if ( this.editor.streamParserKeywords ) { + if ( stream.match(this.editor.streamParserKeywords) ) { + return 'ubol-literal'; + } + } + if ( stream.match(/^\S+/) ) { + return null; + } + stream.next(); + return null; + }, + languageData: { + commentTokens: { line: '#' }, + }, + tokenTable: [ + 'ubol-boundary', + 'ubol-keyword', + 'ubol-comment', + 'ubol-punctuation', + 'ubol-literal', + ], + }; +} + +/******************************************************************************/ + +async function start() { + const editor = new Editor(); + await editor.init(); + dom.on('#editors', 'change', ( ) => { + const select = qs$('#editors'); + const mode = select.value; + if ( mode === editor.mode ) { return; } + editor.selectEditor(mode); + localWrite('dashboard.develop.editor', editor.mode); + }); +} + +let observer = new IntersectionObserver(entries => { + for ( const entry of entries ) { + if ( entry.isIntersecting === false ) { continue; } + start(); + observer.disconnect(); + observer = null; + break; + } +}); +observer.observe(qs$('section[data-pane="develop"]')); + +/******************************************************************************/ diff --git a/platform/mv3/extension/js/dnr-editor.js b/platform/mv3/extension/js/dnr-editor.js new file mode 100644 index 0000000000000..4600d552e80c3 --- /dev/null +++ b/platform/mv3/extension/js/dnr-editor.js @@ -0,0 +1,180 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2014-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { dnr } from './ext-compat.js'; +import { rulesFromText } from './dnr-parser.js'; + +/******************************************************************************/ + +export class DNREditor { + constructor() { + this.validatedRegexes = []; + this.validatedRegexResults = []; + } + + updateView(editor, firstLine, lastLine) { + const { doc } = editor.view.state; + const text = doc.sliceString(firstLine.from, lastLine.to); + const { bad } = rulesFromText(text); + if ( Array.isArray(bad) && bad.length !== 0 ) { + self.cm6.lineErrorAdd(editor.view, bad.map(i => i + firstLine.number)); + } + const entries = self.cm6.findAll( + editor.view, + '\\bregexFilter: (\\S+)', + firstLine.from, + lastLine.to + ); + const regexes = []; + for ( const entry of entries ) { + const regex = entry.match[1]; + const i = this.validatedRegexes.indexOf(regex); + if ( i !== -1 ) { + const reason = this.validatedRegexResults[i]; + if ( reason === true ) { continue; } + self.cm6.spanErrorAdd(editor.view, entry.from+13, entry.to, reason); + } else { + regexes.push(regex); + } + } + this.validateRegexes(editor, regexes); + } + + exportToFile(text, fname) { + const { rules } = rulesFromText(text); + if ( Array.isArray(rules) === false ) { return; } + let ruleId = 1; + for ( const rule of rules ) { + rule.id = ruleId++; + } + return { + fname, + data: JSON.stringify(rules, null, 2), + mime: 'application/json', + }; + } + + async validateRegexes(editor, regexes) { + if ( regexes.length === 0 ) { return; } + const promises = regexes.map(regex => this.validateRegex(regex)); + await Promise.all(promises); + for ( const regex of regexes ) { + const i = this.validatedRegexes.indexOf(regex); + if ( i === -1 ) { continue; } + const reason = this.validatedRegexResults[i]; + if ( reason === true ) { continue; } + const entries = self.cm6.findAll(editor.view, + `(?<=\\bregexFilter: )${RegExp.escape(regex)}` + ); + for ( const entry of entries ) { + self.cm6.spanErrorAdd(editor.view, entry.from, entry.to, reason); + } + } + } + + async validateRegex(regex) { + const details = await dnr.isRegexSupported({ regex }); + const result = details.isSupported || details.reason; + if ( this.validatedRegexes.length > 32 ) { + this.validatedRegexes.pop(); + this.validatedRegexResults.pop(); + } + this.validatedRegexes.unshift(regex); + this.validatedRegexResults.unshift(result); + } + + createTooltipWidget(text) { + const template = document.querySelector('.badmark-tooltip'); + const fragment = template.content.cloneNode(true); + const dom = fragment.querySelector('.badmark-tooltip'); + dom.textContent = text; + return dom; + } + + foldService(state, from) { + const { doc } = state; + const lineFrom = doc.lineAt(from); + if ( this.reFoldable.test(lineFrom.text) === false ) { return null; } + if ( lineFrom.number <= 5 ) { return null ; } + const lineBlockStart = doc.line(lineFrom.number - 5); + if ( this.reFoldCandidates.test(lineBlockStart.text) === false ) { return null; } + for ( let i = lineFrom.number-4; i < lineFrom.number; i++ ) { + const line = doc.line(i); + if ( this.reFoldable.test(line.text) === false ) { return null; } + } + let i = lineFrom.number + 1; + for ( ; i <= doc.lines; i++ ) { + const lineNext = doc.line(i); + if ( this.reFoldable.test(lineNext.text) === false ) { break; } + } + i -= 1; + if ( i === lineFrom.number ) { return null; } + const lineFoldEnd = doc.line(i); + return { from: lineFrom.from+6, to: lineFoldEnd.to }; + } + reFoldable = /^ {4}- \S/; + reFoldCandidates = new RegExp(`^(?: {2})+${[ + 'initiatorDomains', + 'excludedInitiatorDomains', + 'requestDomains', + 'excludedRequestDomains', + ].join('|')}:$`); + + streamParserKeywords = new RegExp(`\\b(${[ + 'block', + 'redirect', + 'allow', + 'modifyHeaders', + 'upgradeScheme', + 'allowAllRequest', + 'append', + 'set', + 'remove', + 'firstParty', + 'thirdParty', + 'true', + 'false', + 'connect', + 'delete', + 'get', + 'head', + 'options', + 'patch', + 'post', + 'put', + 'other', + 'main_frame', + 'sub_frame', + 'stylesheet', + 'script', + 'image', + 'font', + 'object', + 'xmlhttprequest', + 'ping', + 'csp_report', + 'media', + 'websocket', + 'webtransport', + 'webbundle', + 'other', + ].join('|')})\\b`); +}; diff --git a/platform/mv3/extension/js/dnr-parser.js b/platform/mv3/extension/js/dnr-parser.js new file mode 100644 index 0000000000000..37e2d227b1531 --- /dev/null +++ b/platform/mv3/extension/js/dnr-parser.js @@ -0,0 +1,581 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2014-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +/******************************************************************************/ + +const validActionValues = [ + 'block', + 'redirect', + 'allow', + 'upgradeScheme', + 'modifyHeaders', + 'allowAllRequests', +]; + +const validBoolValues = [ + 'false', + 'true', +]; + +const validHeaderOpValues = [ + 'append', + 'remove', + 'set', +]; + +const validDomainTypeValues = [ + 'firstParty', + 'thirdParty', +]; + +const validRequestMethodValues = [ + 'connect', + 'delete', + 'get', + 'head', + 'options', + 'patch', + 'post', + 'put', + 'other', +]; + +const validResourceTypeValues = [ + 'main_frame', + 'sub_frame', + 'stylesheet', + 'script', + 'image', + 'font', + 'object', + 'xmlhttprequest', + 'ping', + 'csp_report', + 'media', + 'websocket', + 'webtransport', + 'webbundle', + 'other', +]; + +/******************************************************************************/ + +function selectParser(scope, rule, node) { + const parser = perScopeParsers[scope.join('.')]; + if ( parser === undefined ) { return false; } + return parser(scope, rule, node); +} + +const perScopeParsers = { + '': function(scope, rule, node) { + const { key, val } = node; + switch ( key ) { + case 'action': + case 'condition': + if ( val !== undefined ) { return false; } + rule[key] = {}; + scope.push(key); + break; + case 'id': { + const n = parseInt(val, 10); + if ( isNaN(n) || n < 1) { return false; } + rule.id = n; + break; + } + case 'priority': { + const n = parseInt(val, 10); + if ( isNaN(n) || n < 1 ) { return false; } + rule.priority = n; + break; + } + default: + return false; + } + return true; + }, + 'action': function(scope, rule, node) { + const { key, val } = node; + switch ( key ) { + case 'type': + if ( validActionValues.includes(val) === false ) { return false; } + rule.action.type = val; + break; + case 'redirect': + rule.action.redirect = {}; + scope.push('redirect'); + break; + case 'requestHeaders': + case 'responseHeaders': + rule.action[key] = []; + scope.push(key); + break; + default: + return false; + } + return true; + }, + 'action.redirect': function(scope, rule, node) { + const { key, val } = node; + switch ( key ) { + case 'extensionPath': + case 'regexSubstitution': + case 'url': + rule.action.redirect[key] = val; + break; + case 'transform': + rule.action.redirect.transform = {}; + scope.push('transform'); + break; + default: + return false; + } + return true; + }, + 'action.redirect.transform': function(scope, rule, node) { + const { key, val } = node; + switch ( key ) { + case 'fragment': + case 'host': + case 'path': + case 'port': + case 'query': + case 'scheme': { + if ( val === undefined ) { return false; } + rule.action.redirect.transform[key] = val; + break; + } + case 'queryTransform': + rule.action.redirect.transform.queryTransform = {}; + scope.push('queryTransform'); + break; + default: + return false; + } + return true; + }, + 'action.redirect.transform.queryTransform': function(scope, rule, node) { + const { key, val } = node; + if ( val !== undefined ) { return false; } + switch ( key ) { + case 'addOrReplaceParams': + case 'removeParams': + rule.action.redirect.transform.queryTransform[key] = []; + scope.push(key); + break; + default: + return false; + } + return true; + }, + 'action.redirect.transform.queryTransform.addOrReplaceParams': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.action.redirect.transform.queryTransform.addOrReplaceParams.push({}); + scope.push('@'); + return selectParser(scope, rule, node); + }, + 'action.redirect.transform.queryTransform.addOrReplaceParams.@': function(scope, rule, node) { + const { key, val } = node; + if ( val === undefined ) { return false; } + const item = rule.action.redirect.transform.queryTransform.addOrReplaceParams.at(-1); + switch ( key ) { + case 'key': + case 'value': + item[key] = val; + break; + case 'replaceOnly': + if ( validBoolValues.includes(val) === false ) { return false; } + item.replaceOnly = val === 'true'; + break; + default: + return false; + } + return true; + }, + 'action.redirect.transform.queryTransform.removeParams': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.action.redirect.transform.queryTransform.removeParams.push(node.val); + return true; + }, + 'action.requestHeaders': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.action.requestHeaders.push({}); + scope.push('@'); + return selectParser(scope, rule, node); + }, + 'action.requestHeaders.@': function(scope, rule, node) { + const { key, val } = node; + const item = rule.action.requestHeaders.at(-1); + switch ( key ) { + case 'header': + case 'value': + item[key] = val; + break; + case 'operation': + if ( validHeaderOpValues.includes(val) === false ) { return false; } + item.operation = val; + break; + default: + return false; + } + return true; + }, + 'action.responseHeaders': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.action.responseHeaders.push({}); + scope.push('@'); + return selectParser(scope, rule, node); + }, + 'action.responseHeaders.@': function(scope, rule, node) { + const { key, val } = node; + const item = rule.action.responseHeaders.at(-1); + switch ( key ) { + case 'header': + case 'value': + item[key] = val; + break; + case 'operation': + if ( validHeaderOpValues.includes(val) === false ) { return false; } + item.operation = val; + break; + default: + return false; + } + return true; + }, + 'condition': function(scope, rule, node) { + const { key, val } = node; + switch ( key ) { + case 'domainType': + if ( validDomainTypeValues.includes(val) === false ) { return false; } + rule.condition.domainType = val; + break; + case 'isUrlFilterCaseSensitive': + if ( validBoolValues.includes(val) === false ) { return false; } + rule.condition.isUrlFilterCaseSensitive = val === 'true'; + break; + case 'regexFilter': + case 'urlFilter': + if ( val === undefined ) { return false; } + rule.condition[key] = val; + break; + case 'initiatorDomains': + case 'excludedInitiatorDomains': + case 'requestDomains': + case 'excludedRequestDomains': + case 'resourceTypes': + case 'excludedResourceTypes': + case 'requestMethods': + case 'excludedRequestMethods': + case 'responseHeaders': + case 'excludedResponseHeaders': + rule.condition[key] = []; + scope.push(key); + break; + case 'tabIds': + rule.condition.tabIds = []; + scope.push('tabIds'); + break; + default: + return false; + } + return true; + }, + 'condition.initiatorDomains': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.condition.initiatorDomains.push(node.val); + return true; + }, + 'condition.excludedInitiatorDomains': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.condition.excludedInitiatorDomains.push(node.val); + return true; + }, + 'condition.domains': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.condition.domains.push(node.val); + return true; + }, + 'condition.excludedDomains': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.condition.excludedDomains.push(node.val); + return true; + }, + 'condition.requestDomains': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.condition.requestDomains.push(node.val); + return true; + }, + 'condition.excludedRequestDomains': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.condition.excludedRequestDomains.push(node.val); + return true; + }, + 'condition.resourceTypes': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + if ( validResourceTypeValues.includes(node.val) === false ) { return false; } + rule.condition.resourceTypes.push(node.val); + return true; + }, + 'condition.excludedResourceTypes': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + if ( validResourceTypeValues.includes(node.val) === false ) { return false; } + rule.condition.excludedResourceTypes.push(node.val); + return true; + }, + 'condition.requestMethods': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + if ( validRequestMethodValues.includes(node.val) === false ) { return false; } + rule.condition.requestMethods.push(node.val); + return true; + }, + 'condition.excludedRequestMethods': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + if ( validRequestMethodValues.includes(node.val) === false ) { return false; } + rule.condition.excludedRequestMethods.push(node.val); + return true; + }, + 'condition.responseHeaders': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.condition.responseHeaders.push({}); + scope.push('@'); + return selectParser(scope, rule, node); + }, + 'condition.responseHeaders.@': function(scope, rule, node) { + const item = rule.condition.responseHeaders.at(-1); + switch ( node.key ) { + case 'header': + if ( node.val === undefined ) { return false; } + item.header = node.val; + break; + case 'values': + case 'excludedValues': + item[node.key] = []; + scope.push(node.key); + break; + default: + return false; + } + return true; + }, + 'condition.responseHeaders.@.values': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + const item = rule.condition.responseHeaders.at(-1); + item.values.push(node.val); + return true; + }, + 'condition.responseHeaders.@.excludedValues': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + const item = rule.condition.responseHeaders.at(-1); + item.excludedValues.push(node.val); + return true; + }, + 'condition.excludedResponseHeaders': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + rule.condition.excludedResponseHeaders.push({}); + scope.push('@'); + return selectParser(scope, rule, node); + }, + 'condition.excludedResponseHeaders.@': function(scope, rule, node) { + const item = rule.condition.excludedResponseHeaders.at(-1); + switch ( node.key ) { + case 'header': + if ( node.val === undefined ) { return false; } + item.header = node.val; + break; + case 'values': + case 'excludedValues': + item[node.key] = []; + scope.push(node.key); + break; + default: + return false; + } + return true; + }, + 'condition.excludedResponseHeaders.@.values': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + const item = rule.condition.excludedResponseHeaders.at(-1); + item.values.push(node.val); + return true; + }, + 'condition.excludedResponseHeaders.@.excludedValues': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + const item = rule.condition.excludedResponseHeaders.at(-1); + item.excludedValues.push(node.val); + return true; + }, + 'condition.tabIds': function(scope, rule, node) { + if ( node.list !== true ) { return false; } + const n = parseInt(node.val, 10); + if ( isNaN(n) || n === 0 ) { return false; } + rule.condition.tabIds.push(n); + }, +}; + +/******************************************************************************/ + +function depthFromIndent(line) { + const match = /^\s*/.exec(line); + const count = match[0].length; + if ( (count & 1) !== 0 ) { return -1; } + return count / 2; +} + +/******************************************************************************/ + +function nodeFromLine(line) { + const match = reNodeParser.exec(line); + const out = {}; + if ( match === null ) { return out; } + if ( match[1] ) { + out.list = true; + } + if ( match[4] ) { + out.val = match[4].trim(); + } else if ( match[3] ) { + out.key = match[2]; + out.val = match[3].trim(); + if ( out.val === "''" ) { out.val = '' }; + } else { + out.key = match[2]; + } + return out; +} + +const reNodeParser = /^\s*(- )?(?:(\S+):( \S.*)?|(\S.*))$/; + +/******************************************************************************/ + +function ruleFromLines(lines, indices) { + const rule = {}; + const bad = []; + const scope = []; + for ( const i of indices ) { + const line = lines[i]; + const depth = depthFromIndent(line); + if ( depth < 0 ) { + bad.push(i); + continue; + } + scope.length = depth; + const node = nodeFromLine(line); + const result = selectParser(scope, rule, node); + if ( result === false ) { + bad.push(i); + } + } + if ( bad.length !== 0 ) { return { bad }; } + return { rule }; +} + +/******************************************************************************/ + +export function rulesFromText(text) { + const rules = []; + const bad = []; + const lines = [ ...text.split(/\n\r|\r\n|\n|\r/), '---' ]; + const indices = []; + for ( let i = 0; i < lines.length; i++ ) { + const line = lines[i].trimEnd(); + if ( line.trim().startsWith('#') ) { continue; } + if ( line !== '---' && line !== '...' ) { + indices.push(i); + continue; + } + // Discard leading empty lines + while ( indices.length !== 0 ) { + const s = lines[indices[0]].trim(); + if ( s.length !== 0 ) { break; } + indices.shift(); + } + // Discard trailing empty lines + while ( indices.length !== 0 ) { + const s = lines[indices.at(-1)].trim(); + if ( s.length !== 0 ) { break; } + indices.pop(); + } + if ( indices.length === 0 ) { continue; } + const result = ruleFromLines(lines, indices); + if ( result.bad ) { + bad.push(...result.bad); + } else if ( result.rule ) { + rules.push(result.rule); + } + indices.length = 0; + } + return { rules, bad }; +} + +/******************************************************************************/ + +function textFromValue(val, depth) { + const indent = ' '.repeat(depth); + switch ( typeof val ) { + case 'boolean': + case 'number': + return `${val}`; + case 'string': + if ( val === '' ) { return "''"; } + return val; + } + const out = []; + if ( Array.isArray(val) ) { + for ( const a of val ) { + const s = textFromValue(a, depth+1); + if ( s === undefined ) { continue; } + out.push(`${indent}- ${s.trimStart()}`); + } + return out.join('\n'); + } + if ( val instanceof Object ) { + for ( const [ a, b ] of Object.entries(val) ) { + const s = textFromValue(b, depth+1); + if ( s === undefined ) { continue; } + if ( b instanceof Object ) { + out.push(`${indent}${a}:\n${s}`); + } else { + out.push(`${indent}${a}: ${s}`); + } + } + return out.join('\n'); + } +} + +/******************************************************************************/ + +export function textFromRules(rules, option = {}) { + if ( Array.isArray(rules) === false ) { + if ( rules instanceof Object === false ) { return; } + rules = [ rules ]; + } + const out = []; + for ( const rule of rules ) { + if ( option.keepId !== true && rule.id ) { rule.id = undefined }; + const text = textFromValue(rule, 0); + if ( text === undefined ) { continue; } + out.push(text, '---' ); + } + if ( out.length !== 0 ) { + out.unshift('---'); + out.push(''); + } + return out.join('\n'); +} diff --git a/platform/mv3/extension/js/ext-compat.js b/platform/mv3/extension/js/ext-compat.js new file mode 100644 index 0000000000000..e5f66f0423a5e --- /dev/null +++ b/platform/mv3/extension/js/ext-compat.js @@ -0,0 +1,103 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2022-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +export const webext = self.browser || self.chrome; +export const dnr = webext.declarativeNetRequest || {}; + +/******************************************************************************/ + +const ruleCompare = (a, b) => a.id - b.id; + +const isSameRules = (a, b) => { + a.sort(ruleCompare); + b.sort(ruleCompare); + return JSON.stringify(a) === JSON.stringify(b); +}; + +/******************************************************************************/ + +export function normalizeDNRRules(rules, ruleIds) { + if ( Array.isArray(rules) === false ) { return rules; } + return Array.isArray(ruleIds) + ? rules.filter(rule => ruleIds.includes(rule.id)) + : rules; +} + +/******************************************************************************/ + +dnr.setAllowAllRules = async function(id, allowed, notAllowed, reverse, priority) { + const [ + beforeDynamicRules, + beforeSessionRules, + ] = await Promise.all([ + dnr.getDynamicRules({ ruleIds: [ id+0 ] }), + dnr.getSessionRules({ ruleIds: [ id+1 ] }), + ]); + const addDynamicRules = []; + const addSessionRules = []; + if ( reverse || allowed.length || notAllowed.length ) { + const rule0 = { + id: id+0, + action: { type: 'allowAllRequests' }, + condition: { + resourceTypes: [ 'main_frame' ], + }, + priority, + }; + if ( allowed.length ) { + rule0.condition.requestDomains = allowed.slice(); + } else if ( notAllowed.length ) { + rule0.condition.excludedRequestDomains = notAllowed.slice(); + } + addDynamicRules.push(rule0); + // https://github.com/uBlockOrigin/uBOL-home/issues/114 + // https://github.com/uBlockOrigin/uBOL-home/issues/247 + const rule1 = { + id: id+1, + action: { type: 'allow' }, + condition: { + tabIds: [ webext.tabs.TAB_ID_NONE ], + }, + priority, + }; + if ( allowed.length ) { + rule1.condition.initiatorDomains = allowed.slice(); + } else if ( notAllowed.length ) { + rule1.condition.excludedInitiatorDomains = notAllowed.slice(); + } + addSessionRules.push(rule1); + } + if ( isSameRules(addDynamicRules, beforeDynamicRules) ) { return false; } + return Promise.all([ + dnr.updateDynamicRules({ + addRules: addDynamicRules, + removeRuleIds: beforeDynamicRules.map(r => r.id), + }), + dnr.updateSessionRules({ + addRules: addSessionRules, + removeRuleIds: beforeSessionRules.map(r => r.id), + }), + ]).then(( ) => + true + ).catch(( ) => + false + ); +}; diff --git a/platform/mv3/extension/js/ext.js b/platform/mv3/extension/js/ext.js index 185fa9c92745d..ea0f90425795a 100644 --- a/platform/mv3/extension/js/ext.js +++ b/platform/mv3/extension/js/ext.js @@ -19,19 +19,11 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; +import { webext } from './ext-compat.js'; /******************************************************************************/ -export const browser = - self.browser instanceof Object && - self.browser instanceof Element === false - ? self.browser - : self.chrome; - -export const dnr = browser.declarativeNetRequest; +export const browser = webext; export const i18n = browser.i18n; export const runtime = browser.runtime; @@ -41,21 +33,8 @@ export const runtime = browser.runtime; // send a message, we try a few more times when the message fails to be sent. export function sendMessage(msg) { - return new Promise((resolve, reject) => { - let i = 5; - const send = ( ) => { - runtime.sendMessage(msg).then(response => { - resolve(response); - }).catch(reason => { - i -= 1; - if ( i <= 0 ) { - reject(reason); - } else { - setTimeout(send, 200); - } - }); - }; - send(); + return runtime.sendMessage(msg).catch(reason => { + console.log(reason); }); } @@ -68,7 +47,7 @@ export async function localRead(key) { const bin = await browser.storage.local.get(key); if ( bin instanceof Object === false ) { return; } return bin[key] ?? undefined; - } catch(ex) { + } catch { } } @@ -84,6 +63,17 @@ export async function localRemove(key) { return browser.storage.local.remove(key); } +export async function localKeys() { + if ( browser.storage instanceof Object === false ) { return; } + if ( browser.storage.local instanceof Object === false ) { return; } + if ( browser.storage.local.getKeys ) { + return browser.storage.local.getKeys(); + } + const bin = await browser.storage.local.get(null); + if ( bin instanceof Object === false ) { return; } + return Object.keys(bin); +} + /******************************************************************************/ export async function sessionRead(key) { @@ -93,7 +83,7 @@ export async function sessionRead(key) { const bin = await browser.storage.session.get(key); if ( bin instanceof Object === false ) { return; } return bin[key] ?? undefined; - } catch(ex) { + } catch { } } @@ -103,16 +93,22 @@ 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; } return bin[key] ?? undefined; - } catch(ex) { + } catch { } } diff --git a/platform/mv3/extension/js/fetch.js b/platform/mv3/extension/js/fetch.js index 5570159fd717a..675a37eba9c01 100644 --- a/platform/mv3/extension/js/fetch.js +++ b/platform/mv3/extension/js/fetch.js @@ -19,10 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - /******************************************************************************/ function fetchJSON(path) { diff --git a/platform/mv3/extension/js/filter-lists.js b/platform/mv3/extension/js/filter-lists.js new file mode 100644 index 0000000000000..1cb54e78b1501 --- /dev/null +++ b/platform/mv3/extension/js/filter-lists.js @@ -0,0 +1,459 @@ +/******************************************************************************* + + 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'; +import { hashFromIterable } from './dashboard.js'; + +/******************************************************************************/ + +export const rulesetMap = new Map(); + +let cachedRulesetData = {}; +let hideUnusedSet = new Set([ 'ads', '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 rulesetDetails = rulesetMap.get(rulesetId); + if ( rulesetDetails === undefined ) { return; } + const { rules, filters } = rulesetDetails; + let ruleCount = rules.plain + rules.regex; + if ( cachedRulesetData.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.enabled === true); + 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.group === 'default' + ), + ], [ + 'ads', + rulesetDetails.filter(ruleset => + ruleset.group === 'ads' + ), + ], [ + 'privacy', + rulesetDetails.filter(ruleset => + ruleset.group === 'privacy' + ), + ], [ + 'malware', + rulesetDetails.filter(ruleset => + ruleset.group === 'malware' + ), + ], [ + 'annoyances', + rulesetDetails.filter(ruleset => + ruleset.group === 'annoyances' + ), + ], [ + 'misc', + rulesetDetails.filter(ruleset => + 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'); + + const unmodified = hashFromIterable(enabledRulesets) === + hashFromIterable(cachedRulesetData.enabledRulesets); + if ( unmodified ) { 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/filter-manager.js b/platform/mv3/extension/js/filter-manager.js new file mode 100644 index 0000000000000..282c972438cdb --- /dev/null +++ b/platform/mv3/extension/js/filter-manager.js @@ -0,0 +1,157 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2022-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { + browser, + localKeys, + localRead, + localRemove, + localWrite, +} from './ext.js'; + +import { + intersectHostnameIters, + matchesFromHostnames, + strArrayEq, + subtractHostnameIters, +} from './utils.js'; + +/******************************************************************************/ + +export async function selectorsFromCustomFilters(hostname) { + const promises = []; + let hn = hostname; + while ( hn !== '' ) { + promises.push(localRead(`site.${hn}`)); + const pos = hn.indexOf('.'); + if ( pos === -1 ) { break; } + hn = hn.slice(pos + 1); + } + const results = await Promise.all(promises); + const out = []; + for ( let i = 0; i < promises.length; i++ ) { + const selectors = results[i]; + if ( selectors === undefined ) { continue; } + selectors.forEach(selector => { out.push(selector.slice(1)); }); + } + return out.sort(); +} + +/******************************************************************************/ + +export async function hasCustomFilters(hostname) { + const selectors = await selectorsFromCustomFilters(hostname); + return selectors?.length ?? 0; +} + +/******************************************************************************/ + +export async function injectCustomFilters(tabId, frameId, hostname) { + const selectors = await selectorsFromCustomFilters(hostname); + if ( selectors.length === 0 ) { return; } + await browser.scripting.insertCSS({ + css: `${selectors.join(',\n')}{display:none!important;}`, + origin: 'USER', + target: { tabId, frameIds: [ frameId ] }, + }).catch(reason => { + console.log(reason); + }); + return selectors; +} + +/******************************************************************************/ + +export async function uninjectCustomFilters(tabId, frameId, hostname) { + const selectors = await selectorsFromCustomFilters(hostname); + if ( selectors.length === 0 ) { return; } + return browser.scripting.removeCSS({ + css: `${selectors.join(',\n')}{display:none!important;}`, + origin: 'USER', + target: { tabId, frameIds: [ frameId ] }, + }).catch(reason => { + console.log(reason); + }); +} + +/******************************************************************************/ + +export async function registerCustomFilters(context) { + const storageKeys = await localKeys() || []; + const siteKeys = storageKeys.filter(a => a.startsWith('site.')); + if ( siteKeys.length === 0 ) { return; } + + const { none } = context.filteringModeDetails; + let hostnames = siteKeys.map(a => a.slice(5)); + if ( none.has('all-urls') ) { + const { basic, optimal, complete } = context.filteringModeDetails; + hostnames = intersectHostnameIters(hostnames, [ + ...basic, ...optimal, ...complete + ]); + } else if ( none.size !== 0 ) { + hostnames = [ ...subtractHostnameIters(hostnames, none) ]; + } + if ( hostnames.length === 0 ) { return; } + + const registered = context.before.get('css-user'); + context.before.delete('css-user'); // Important! + + const directive = { + id: 'css-user', + js: [ '/js/scripting/css-user.js' ], + matches: matchesFromHostnames(hostnames), + runAt: 'document_start', + }; + + if ( registered === undefined ) { + context.toAdd.push(directive); + } else if ( strArrayEq(registered.matches, directive.matches) === false ) { + context.toRemove.push('css-user'); + context.toAdd.push(directive); + } +} + +/******************************************************************************/ + +export async function addCustomFilter(hostname, selector) { + const key = `site.${hostname}`; + const selectors = await localRead(key) || []; + const filter = `0${selector}`; + if ( selectors.includes(filter) ) { return false; } + selectors.push(filter); + selectors.sort(); + await localWrite(key, selectors); + return true; +} + +/******************************************************************************/ + +export async function removeCustomFilter(hostname, selector) { + const key = `site.${hostname}`; + const selectors = await localRead(key); + if ( selectors === undefined ) { return false; } + const i = selectors.indexOf(`0${selector}`); + if ( i === -1 ) { return false; } + selectors.splice(i, 1); + await selectors.length !== 0 + ? localWrite(key, selectors) + : localRemove(key); + return true; +} 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-editor.js b/platform/mv3/extension/js/mode-editor.js new file mode 100644 index 0000000000000..9e86eade503a7 --- /dev/null +++ b/platform/mv3/extension/js/mode-editor.js @@ -0,0 +1,91 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2014-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { + modesFromText, + textFromModes, +} from './mode-parser.js'; +import { i18n$ } from './i18n.js'; +import { sendMessage } from './ext.js'; + +/******************************************************************************/ + +export class ModeEditor { + constructor(editor) { + this.editor = editor; + this.bc = null; + } + + on() { + if ( this.bc !== null ) { return; } + this.bc = new self.BroadcastChannel('uBOL'); + this.bc.onmessage = ev => { + const message = ev.data; + if ( message instanceof Object === false ) { return; } + if ( message.filteringModeDetails === undefined ) { return; } + // TODO: merge with ongoing edits? + const text = textFromModes(message.filteringModeDetails); + this.editor.setEditorText(text, true); + }; + } + + off() { + if ( this.bc === null ) { return; } + this.bc.onmessage = null; + this.bc = null; + } + + async getText() { + const modes = await sendMessage({ what: 'getFilteringModeDetails' }); + return textFromModes(modes); + } + + async saveEditorText(editor) { + const { modes } = modesFromText(editor.getEditorText()); + if ( modes instanceof Object === false ) { return; } + const modesAfter = await sendMessage({ what: 'setFilteringModeDetails', modes }); + const text = textFromModes(modesAfter); + editor.setEditorText(text); + return true; + } + + updateView(editor, firstLine, lastLine) { + const { doc } = editor.view.state; + const text = doc.sliceString(firstLine.from, lastLine.to); + const { bad } = modesFromText(text, true); + if ( Array.isArray(bad) && bad.length !== 0 ) { + self.cm6.lineErrorAdd(editor.view, bad.map(i => i + firstLine.number)); + } + } + + newlineAssistant = { + 'no filtering:': ' - ', + 'basic:': ' - ', + 'optimal:': ' - ', + 'complete:': ' - ', + [`${i18n$('filteringMode0Name')}:`]: ' - ', + [`${i18n$('filteringMode1Name')}:`]: ' - ', + [`${i18n$('filteringMode2Name')}:`]: ' - ', + [`${i18n$('filteringMode3Name')}:`]: ' - ', + }; + + ioAccept = '.json,application/json'; +}; diff --git a/platform/mv3/extension/js/mode-manager.js b/platform/mv3/extension/js/mode-manager.js index e75dbeef58339..ae139a82507f0 100644 --- a/platform/mv3/extension/js/mode-manager.js +++ b/platform/mv3/extension/js/mode-manager.js @@ -19,31 +19,27 @@ 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, + hasBroadHostPermissions, hostnamesFromMatches, isDescendantHostnameOfIter, toBroaderHostname, } from './utils.js'; import { - TRUSTED_DIRECTIVE_BASE_RULE_ID, - getDynamicRules -} from './ruleset-manager.js'; + browser, + localRead, localWrite, + sessionRead, sessionWrite, +} from './ext.js'; + +import { + rulesetConfig, + saveRulesetConfig, +} from './config.js'; + +import { adminReadEx } from './admin.js'; +import { filteringModesToDNR } from './ruleset-manager.js'; /******************************************************************************/ @@ -79,18 +75,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 +213,54 @@ 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([ + let [ + userModes = { optimal: [ 'all-urls' ] }, + adminDefaultFiltering, + adminNoFiltering, + ] = await Promise.all([ localRead('filteringModeDetails'), - localRead('adminNoFiltering'), + adminReadEx('defaultFiltering'), + adminReadEx('noFiltering'), ]); - if ( userModes === undefined ) { - userModes = { basic: [ 'all-urls' ] }; - } userModes = unserializeModeDetails(userModes); - if ( Array.isArray(adminNoFiltering) ) { + if ( adminDefaultFiltering !== undefined ) { + const modefromName = { + none: MODE_NONE, + basic: MODE_BASIC, + optimal: MODE_OPTIMAL, + complete: MODE_COMPLETE, + }; + const adminDefaultFilteringMode = modefromName[adminDefaultFiltering]; + if ( adminDefaultFilteringMode !== undefined ) { + applyFilteringMode(userModes, 'all-urls', adminDefaultFilteringMode); + } + } + if ( Array.isArray(adminNoFiltering) && adminNoFiltering.length !== 0 ) { + if ( adminNoFiltering.includes('-*') ) { + userModes.none.clear(); + } 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,90 +272,36 @@ async function writeFilteringModeDetails(afterDetails) { localWrite('filteringModeDetails', data); sessionWrite('filteringModeDetails', data); readFilteringModeDetails.cache = unserializeModeDetails(data); - - Promise.all([ + return Promise.all([ getDefaultFilteringMode(), - getTrustedSites(), + hasBroadHostPermissions(), + localWrite('filteringModeDetails', data), + sessionWrite('filteringModeDetails', data), ]).then(results => { broadcastMessage({ defaultFilteringMode: results[0], - trustedSites: Array.from(results[1]), + hasOmnipotence: results[1], + filteringModeDetails: readFilteringModeDetails.cache, }); }); } /******************************************************************************/ -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() { +export async function getFilteringModeDetails(serializable = false) { const actualDetails = await readFilteringModeDetails(); - return { + const out = { none: new Set(actualDetails.none), basic: new Set(actualDetails.basic), optimal: new Set(actualDetails.optimal), complete: new Set(actualDetails.complete), }; + return serializable ? serializeModeDetails(out) : out; +} + +export async function setFilteringModeDetails(details) { + await localWrite('filteringModeDetails', serializeModeDetails(details)); + await readFilteringModeDetails(true); } /******************************************************************************/ @@ -384,59 +330,45 @@ export function setDefaultFilteringMode(afterLevel) { /******************************************************************************/ -export async function getTrustedSites() { - const filteringModes = await getFilteringModeDetails(); - return filteringModes.none; -} - -export async function setTrustedSites(hostnames) { - const filteringModes = await getFilteringModeDetails(); - const { none } = filteringModes; - const hnSet = new Set(hostnames); - let modified = false; - for ( const hn of none ) { - if ( hnSet.has(hn) ) { - hnSet.delete(hn); - } else { - none.delete(hn); - modified = true; - } - } - for ( const hn of hnSet ) { - const level = applyFilteringMode(filteringModes, hn, MODE_NONE); - if ( level !== MODE_NONE ) { continue; } - modified = true; - } - if ( modified === false ) { return; } - return writeFilteringModeDetails(filteringModes); -} - -/******************************************************************************/ - export async function syncWithBrowserPermissions() { - const [ permissions, beforeMode ] = await Promise.all([ + const [ + permissions, + beforeMode, + ] = await Promise.all([ browser.permissions.getAll(), getDefaultFilteringMode(), ]); const allowedHostnames = new Set(hostnamesFromMatches(permissions.origins || [])); + const hasBroadHostPermissions = allowedHostnames.has('all-urls'); + const broadHostPermissionsToggled = + hasBroadHostPermissions !== rulesetConfig.hasBroadHostPermissions; let modified = false; - if ( beforeMode > MODE_BASIC && allowedHostnames.has('all-urls') === false ) { + if ( beforeMode > MODE_BASIC && hasBroadHostPermissions === false ) { await setDefaultFilteringMode(MODE_BASIC); modified = true; + } else if ( beforeMode === MODE_BASIC && hasBroadHostPermissions && broadHostPermissionsToggled ) { + await setDefaultFilteringMode(MODE_OPTIMAL); + modified = true; + } + if ( broadHostPermissionsToggled ) { + rulesetConfig.hasBroadHostPermissions = hasBroadHostPermissions; + saveRulesetConfig(); } const afterMode = await getDefaultFilteringMode(); - if ( afterMode > MODE_BASIC ) { return false; } + if ( afterMode > MODE_BASIC ) { return afterMode !== beforeMode; } const filteringModes = await getFilteringModeDetails(); - const { optimal, complete } = filteringModes; - for ( const hn of optimal ) { - if ( allowedHostnames.has(hn) ) { continue; } - optimal.delete(hn); - modified = true; - } - for ( const hn of complete ) { - if ( allowedHostnames.has(hn) ) { continue; } - complete.delete(hn); - modified = true; + if ( allowedHostnames.has('all-urls') === false ) { + const { optimal, complete } = filteringModes; + for ( const hn of optimal ) { + if ( allowedHostnames.has(hn) ) { continue; } + optimal.delete(hn); + modified = true; + } + for ( const hn of complete ) { + if ( allowedHostnames.has(hn) ) { continue; } + complete.delete(hn); + modified = true; + } } await writeFilteringModeDetails(filteringModes); return modified; diff --git a/platform/mv3/extension/js/mode-parser.js b/platform/mv3/extension/js/mode-parser.js new file mode 100644 index 0000000000000..719a29efe0bc3 --- /dev/null +++ b/platform/mv3/extension/js/mode-parser.js @@ -0,0 +1,211 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2014-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { i18n$ } from './i18n.js'; +import punycode from './punycode.js'; + +/******************************************************************************/ + +function selectParser(scope, modes, node) { + const parser = perScopeParsers[scope.join('.')]; + if ( parser === undefined ) { return false; } + return parser(scope, modes, node); +} + +const validModes = [ + 'none', + 'basic', + 'optimal', + 'complete', +]; + +const uglyModeNames = { + [i18n$('filteringMode0Name')]: 'none', + [i18n$('filteringMode1Name')]: 'basic', + [i18n$('filteringMode2Name')]: 'optimal', + [i18n$('filteringMode3Name')]: 'complete', +}; + +const prettyModeNames = { + none: i18n$('filteringMode0Name'), + basic: i18n$('filteringMode1Name'), + optimal: i18n$('filteringMode2Name'), + complete: i18n$('filteringMode3Name'), +}; + +const perScopeParsers = { + '': function(scope, modes, node) { + const { key, val } = node; + switch ( key ) { + case 'none': + case 'basic': + case 'optimal': + case 'complete': + case prettyModeNames.none: + case prettyModeNames.basic: + case prettyModeNames.optimal: + case prettyModeNames.complete: { + const mode = uglyModeNames[key] || key; + if ( val !== undefined ) { return false; } + modes[mode] ||= []; + scope.push(mode); + break; + } + default: + return false; + } + return true; + }, + none: function(scope, modes, node) { + return addHostnameToMode(modes, 'none', node) + }, + basic: function(scope, modes, node) { + return addHostnameToMode(modes, 'basic', node) + }, + optimal: function(scope, modes, node) { + return addHostnameToMode(modes, 'optimal', node) + }, + complete: function(scope, modes, node) { + return addHostnameToMode(modes, 'complete', node) + }, +}; + +const addHostnameToMode = (modes, mode, node) => { + if ( node.list !== true ) { return false; } + modes[mode].push(punycode.toASCII(node.val)); +}; + +/******************************************************************************/ + +function depthFromIndent(line) { + const match = /^\s*/.exec(line); + const count = match[0].length; + if ( (count & 1) !== 0 ) { return -1; } + return count / 2; +} + +/******************************************************************************/ + +function nodeFromLine(line) { + const match = reNodeParser.exec(line); + const out = {}; + if ( match === null ) { return out; } + if ( match[1] ) { + out.list = true; + } + if ( match[4] ) { + out.val = match[4].trim(); + } else if ( match[3] ) { + out.key = match[2]; + out.val = match[3].trim(); + if ( out.val === "''" ) { out.val = '' }; + } else { + out.key = match[2]; + } + return out; +} + +const reNodeParser = /^\s*(- )?(?:([^:]+):( \S.*)?|(\S.*))$/; + +/******************************************************************************/ + +export function modesFromText(text, justbad = false) { + const lines = [ ...text.split(/\n\r|\r\n|\n|\r/) ]; + const indices = []; + for ( let i = 0; i < lines.length; i++ ) { + const line = lines[i].trimEnd(); + if ( line.trim().startsWith('#') ) { continue; } + indices.push(i); + } + // Discard leading empty lines + while ( indices.length !== 0 ) { + const s = lines[indices[0]].trim(); + if ( s.length !== 0 ) { break; } + indices.shift(); + } + // Discard trailing empty lines + while ( indices.length !== 0 ) { + const s = lines[indices.at(-1)].trim(); + if ( s.length !== 0 ) { break; } + indices.pop(); + } + // Parse + const modes = {}; + const bad = []; + const scope = []; + for ( const i of indices ) { + const line = lines[i]; + const depth = depthFromIndent(line); + if ( depth < 0 ) { + bad.push(i); + continue; + } + scope.length = depth; + const node = nodeFromLine(line); + const result = selectParser(scope, modes, node); + if ( result === false ) { + bad.push(i); + } + } + if ( justbad ) { + return bad.length !== 0 ? { bad } : { }; + } + // Ensure all modes are present, and that one mode is the default one + const seen = new Map(); + let defaultMode = ''; + for ( const mode of validModes ) { + modes[mode] = new Set(modes[mode]); + if ( modes[mode].has('all-urls') ) { + defaultMode = mode; + } + for ( const hn of modes[mode] ) { + if ( seen.has(hn) ) { + modes[seen.get(hn)].delete(hn); + } + seen.set(hn, mode); + } + } + if ( defaultMode === '' ) { + defaultMode = 'optimal'; + } + modes[defaultMode].clear(); + modes[defaultMode].add('all-urls'); + for ( const mode of validModes ) { + modes[mode] = Array.from(modes[mode]); + } + return { modes }; +} + +/******************************************************************************/ + +export function textFromModes(modes) { + const out = []; + for ( const mode of validModes ) { + const hostnames = modes[mode]; + if ( hostnames === undefined ) { continue; } + out.push(`${prettyModeNames[mode]}:`); + for ( const hn of hostnames ) { + out.push(` - ${punycode.toUnicode(hn)}`); + } + } + out.push(''); + return out.join('\n'); +} diff --git a/platform/mv3/extension/js/picker-ui.js b/platform/mv3/extension/js/picker-ui.js new file mode 100644 index 0000000000000..bb43565547fb9 --- /dev/null +++ b/platform/mv3/extension/js/picker-ui.js @@ -0,0 +1,435 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { dom, qs$, qsa$ } from './dom.js'; +import { localRead, localWrite } from './ext.js'; +import { toolOverlay } from './tool-overlay-ui.js'; + +/******************************************************************************/ + +let selectorPartsDB = new Map(); +let sliderParts = []; +let sliderPartsPos = -1; +let previewCSS = ''; + +/******************************************************************************/ + +function isValidSelector(selector) { + isValidSelector.error = undefined; + if ( selector === '' ) { return false; } + try { + void document.querySelector(`${selector},a`); + } catch (reason) { + isValidSelector.error = reason; + return false; + } + return true; +} + +/******************************************************************************/ + +function onSvgTouch(ev) { + if ( ev.type === 'touchstart' ) { + onSvgTouch.x0 = ev.touches[0].screenX; + onSvgTouch.y0 = ev.touches[0].screenY; + onSvgTouch.t0 = ev.timeStamp; + return; + } + if ( onSvgTouch.x0 === undefined ) { return; } + const stopX = ev.changedTouches[0].screenX; + const stopY = ev.changedTouches[0].screenY; + const distance = Math.sqrt( + Math.pow(stopX - onSvgTouch.x0, 2) + + Math.pow(stopY - onSvgTouch.y0, 2) + ); + // Interpret touch events as a tap if: + // - Swipe is not valid; and + // - The time between start and stop was less than 200ms. + const duration = ev.timeStamp - onSvgTouch.t0; + if ( distance >= 32 || duration >= 200 ) { return; } + onSvgClicked({ + type: 'touch', + target: ev.target, + clientX: ev.changedTouches[0].pageX, + clientY: ev.changedTouches[0].pageY, + }); + ev.preventDefault(); +} +onSvgTouch.x0 = onSvgTouch.y0 = 0; +onSvgTouch.t0 = 0; + +/******************************************************************************/ + +function onSvgClicked(ev) { + // Unpause picker if: + // - click outside dialog AND + // - not in preview mode + if ( dom.cl.has(dom.root, 'paused') ) { + if ( dom.cl.has(dom.root, 'preview') ) { + updatePreview(false); + } + unpausePicker(); + return; + } + // Force dialog to always be visible when using a touch-driven device. + if ( ev.type === 'touch' ) { + dom.cl.add(dom.root, 'show'); + } + toolOverlay.postMessage({ + what: 'candidatesAtPoint', + mx: ev.clientX, + my: ev.clientY, + broad: ev.ctrlKey, + }).then(details => { + showDialog(details); + }); +} + +/******************************************************************************/ + +function onKeyPressed(ev) { + if ( ev.key === 'Escape' || ev.which === 27 ) { + quitPicker(); + return; + } +} + +/******************************************************************************/ + +function onMinimizeClicked() { + if ( dom.cl.has(dom.root, 'paused') === false ) { + pausePicker(); + highlightCandidate(); + return; + } + dom.cl.toggle(dom.root, 'minimized'); +} + +/******************************************************************************/ + +function onFilterTextChanged() { + highlightCandidate(); +} + +/******************************************************************************/ + +function toggleView(view, persist = false) { + dom.root.dataset.view = `${view}`; + if ( persist !== true ) { return; } + localWrite('picker.view', dom.root.dataset.view); +} + +function onViewToggled(dir) { + let view = parseInt(dom.root.dataset.view, 10); + view += dir; + if ( view < 0 ) { view = 0; } + if ( view > 2 ) { view = 2; } + toggleView(view, true); +} + +/******************************************************************************/ + +function selectorFromCandidates() { + const selectorParts = []; + let liPrevious = null; + for ( const li of qsa$('#candidateFilters li') ) { + const selector = []; + for ( const span of qsa$(li, '.on[data-part]') ) { + selector.push(span.textContent); + } + if ( selector.length !== 0 ) { + if ( liPrevious !== null ) { + if ( li.previousElementSibling === liPrevious ) { + selectorParts.unshift(' > '); + } else if ( liPrevious !== li ) { + selectorParts.unshift(' '); + } + } + liPrevious = li; + selectorParts.unshift(selector.join('')); + } + } + return selectorParts.join(''); +} + +/******************************************************************************/ + +function onSliderChanged(ev) { + updateSlider(Math.round(ev.target.valueAsNumber)); +} + +function updateSlider(i) { + if ( i === sliderPartsPos ) { return; } + sliderPartsPos = i; + dom.cl.remove('#candidateFilters [data-part]', 'on'); + const parts = sliderParts[i]; + for ( const address of parts ) { + dom.cl.add(`#candidateFilters [data-part="${address}"]`, 'on'); + } + const selector = selectorFromCandidates(); + qs$('textarea').value = selector; + highlightCandidate(); +} + +/******************************************************************************/ + +function updateElementCount(details) { + const { count, error } = details; + const span = qs$('#resultsetCount'); + if ( error ) { + span.textContent = 'Error'; + span.setAttribute('title', error); + } else { + span.textContent = count; + span.removeAttribute('title'); + } + const disabled = Boolean(count) === false ? '' : null; + dom.attr('#create', 'disabled', disabled); + updatePreview(); +} + +/******************************************************************************/ + +function onPreviewClicked() { + dom.cl.toggle(dom.root, 'preview'); + updatePreview(); +} + +function updatePreview(state) { + if ( state === undefined ) { + state = dom.cl.has(dom.root, 'preview'); + } else { + dom.cl.toggle(dom.root, 'preview', state) + } + if ( previewCSS !== '' ) { + toolOverlay.postMessage({ what: 'removeCSS', css: previewCSS }); + previewCSS = ''; + } + if ( state === false ) { return; } + const selector = qs$('textarea').value; + if ( isValidSelector(selector) === false ) { return; } + previewCSS = `${selector}{display:none!important;}`; + toolOverlay.postMessage({ what: 'insertCSS', css: previewCSS }); +} + +/******************************************************************************/ + +async function onCreateClicked() { + const selector = qs$('textarea').value; + if ( isValidSelector(selector) === false ) { return; } + await toolOverlay.postMessage({ what: 'uninjectCustomFilters' }).then(( ) => + toolOverlay.sendMessage({ + what: 'addCustomFilter', + hostname: toolOverlay.url.hostname, + selector, + }) + ).then(( ) => + toolOverlay.postMessage({ what: 'injectCustomFilters' }) + ); + qs$('textarea').value = ''; + dom.cl.remove(dom.root, 'preview'); + quitPicker(); +} + +/******************************************************************************/ + +function attributeNameFromSelector(part) { + const pos = part.search(/\^?=/); + return part.slice(1, pos); +} + +/******************************************************************************/ + +function onCandidateClicked(ev) { + const target = ev.target; + if ( target.matches('[data-part]') ) { + const address = target.dataset.part; + const part = selectorPartsDB.get(parseInt(address, 10)); + if ( part.startsWith('[') ) { + if ( target.textContent === part ) { + target.textContent = `[${attributeNameFromSelector(part)}]`; + dom.cl.remove(target, 'on'); + } else if ( dom.cl.has(target, 'on') ) { + target.textContent = part; + } else { + dom.cl.add(target, 'on'); + } + } else { + dom.cl.toggle(target, 'on'); + } + } else if ( target.matches('li') ) { + if ( qs$(target, ':scope > span:not(.on)') !== null ) { + dom.cl.add(qsa$(target, ':scope > [data-part]:not(.on)'), 'on'); + } else { + dom.cl.remove(qsa$(target, ':scope > [data-part]'), 'on'); + } + } + const selector = selectorFromCandidates(); + qs$('textarea').value = selector; + highlightCandidate(); +} + +/******************************************************************************/ + +function showDialog(msg) { + pausePicker(); + + /* global */selectorPartsDB = new Map(msg.partsDB); + const { listParts } = msg; + const root = qs$('#candidateFilters'); + const ul = qs$(root, 'ul'); + while ( ul.firstChild !== null ) { + ul.firstChild.remove(); + } + for ( const parts of listParts ) { + const li = document.createElement('li'); + for ( const address of parts ) { + const span = document.createElement('span'); + const part = selectorPartsDB.get(address); + span.dataset.part = address; + if ( part.startsWith('[') ) { + span.textContent = `[${attributeNameFromSelector(part)}]`; + } else { + span.textContent = part; + } + li.append(span); + } + ul.appendChild(li); + } + + /* global */sliderParts = msg.sliderParts; + /* global */sliderPartsPos = -1; + const slider = qs$('#slider'); + const last = sliderParts.length - 1; + dom.attr(slider, 'max', last); + dom.attr(slider, 'value', last); + dom.attr(slider, 'disabled', last !== 0 ? null : ''); + slider.value = last; + updateSlider(last); +} + +/******************************************************************************/ + +function highlightCandidate() { + const selector = qs$('textarea').value; + if ( isValidSelector(selector) === false ) { + toolOverlay.postMessage({ what: 'unhighlight' }); + updateElementCount({ count: 0, error: isValidSelector.error }); + return; + } + toolOverlay.postMessage({ + what: 'highlightFromSelector', + selector, + }).then(result => { + updateElementCount(result); + }); +} + +/******************************************************************************* + * + * paused: + * - select element mode disabled + * - preview mode enabled or disabled + * - dialog unminimized + * + * unpaused: + * - select element mode enabled + * - preview mode disabled + * - dialog minimized + * + * */ + +function pausePicker() { + dom.cl.add(dom.root, 'paused'); + dom.cl.remove(dom.root, 'minimized'); + toolOverlay.highlightElementUnderMouse(false); +} + +function unpausePicker() { + dom.cl.remove(dom.root, 'paused', 'preview'); + dom.cl.add(dom.root, 'minimized'); + updatePreview(); + toolOverlay.postMessage({ + what: 'togglePreview', + state: false, + }); + toolOverlay.highlightElementUnderMouse(true); +} + +/******************************************************************************/ + +function startPicker() { + toolOverlay.postMessage({ what: 'startTool' }); + + localRead('picker.view').then(value => { + if ( Boolean(value) === false ) { return; } + toggleView(value); + }); + + self.addEventListener('keydown', onKeyPressed, true); + dom.on('svg#overlay', 'click', onSvgClicked); + dom.on('svg#overlay', 'touchstart', onSvgTouch, { passive: true }); + dom.on('svg#overlay', 'touchend', onSvgTouch); + dom.on('#minimize', 'click', onMinimizeClicked); + dom.on('textarea', 'input', onFilterTextChanged); + dom.on('#quit', 'click', quitPicker); + dom.on('#slider', 'input', onSliderChanged); + dom.on('#pick', 'click', resetPicker); + dom.on('#preview', 'click', onPreviewClicked); + dom.on('#moreOrLess > span:first-of-type', 'click', ( ) => { onViewToggled(1); }); + dom.on('#moreOrLess > span:last-of-type', 'click', ( ) => { onViewToggled(-1); }); + dom.on('#create', 'click', ( ) => { onCreateClicked(); }); + dom.on('#candidateFilters ul', 'click', onCandidateClicked); + toolOverlay.highlightElementUnderMouse(true); +} + +/******************************************************************************/ + +function quitPicker() { + updatePreview(false); + toolOverlay.stop(); +} + +/******************************************************************************/ + +function resetPicker() { + toolOverlay.postMessage({ what: 'unhighlight' }); + unpausePicker(); +} + +/******************************************************************************/ + +function onMessage(msg) { + switch ( msg.what ) { + case 'startTool': + startPicker(); + break; + default: + break; + } +} + +/******************************************************************************/ + +// Wait for the content script to establish communication +toolOverlay.start(onMessage); + +/******************************************************************************/ diff --git a/platform/mv3/extension/js/popup.js b/platform/mv3/extension/js/popup.js index 29b993b24aa39..ce0fe08da379b 100644 --- a/platform/mv3/extension/js/popup.js +++ b/platform/mv3/extension/js/popup.js @@ -19,28 +19,16 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - -/******************************************************************************/ - -import { - browser, - runtime, - sendMessage, - localRead, localWrite, -} from './ext.js'; - +import { browser, runtime, sendMessage } from './ext.js'; import { dom, qs$ } from './dom.js'; -import { i18n, i18n$ } from './i18n.js'; +import { i18n$ } from './i18n.js'; import punycode from './punycode.js'; /******************************************************************************/ const popupPanelData = {}; const currentTab = {}; -let tabHostname = ''; +const tabURL = new URL(runtime.getURL('/')); /******************************************************************************/ @@ -50,6 +38,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,18 +62,28 @@ 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); if ( afterLevel > 1 ) { + if ( beforeLevel <= 1 ) { + sendMessage({ + what: 'setPendingFilteringMode', + tabId: currentTab.id, + url: tabURL.href, + hostname: targetHostname, + beforeLevel, + afterLevel, + }); + } let granted = false; try { granted = await browser.permissions.request({ origins: [ `*://*.${targetHostname}/*` ], }); - } catch(ex) { + } catch { } if ( granted !== true ) { setFilteringMode(beforeLevel); @@ -97,7 +103,14 @@ async function commitFilteringMode() { setFilteringMode(actualLevel); } if ( actualLevel !== beforeLevel && popupPanelData.autoReload ) { - browser.tabs.reload(currentTab.id); + const justReload = tabURL.href === currentTab.url; + self.setTimeout(( ) => { + if ( justReload ) { + browser.tabs.reload(currentTab.id); + } else { + browser.tabs.update(currentTab.id, { url: tabURL.href }); + } + }, 437); } } @@ -189,8 +202,7 @@ dom.on( ev => { const span = ev.target; const level = parseInt(span.dataset.level, 10); - dom.text( - '#filteringModeText > span:nth-of-type(2)', + dom.text('#filteringModeText > span:nth-of-type(2)', i18n$(`filteringMode${level}Name`) ); } @@ -207,68 +219,73 @@ dom.on( /******************************************************************************/ -// The popup panel is made of sections. Visibility of sections can be -// toggled on/off. +dom.on('#gotoMatchedRules', 'click', ev => { + if ( ev.isTrusted !== true ) { return; } + if ( ev.button !== 0 ) { return; } + sendMessage({ + what: 'showMatchedRules', + tabId: currentTab.id, + }); +}); -const maxNumberOfSections = 2; +/******************************************************************************/ -const sectionBitsFromAttribute = function() { - const value = dom.body.dataset.section; - if ( value === '' ) { return 0; } - let bits = 0; - for ( const c of value.split(' ') ) { - bits |= 1 << (c.charCodeAt(0) - 97); - } - return bits; -}; - -const sectionBitsToAttribute = function(bits) { - if ( typeof bits !== 'number' ) { return; } - if ( isNaN(bits) ) { return; } - const value = []; - for ( let i = 0; i < maxNumberOfSections; i++ ) { - const bit = 1 << i; - if ( (bits & bit) === 0 ) { continue; } - value.push(String.fromCharCode(97 + i)); - } - dom.body.dataset.section = value.join(' '); -}; - -async function toggleSections(more) { - let currentBits = sectionBitsFromAttribute(); - let newBits = currentBits; - for ( let i = 0; i < maxNumberOfSections; i++ ) { - const bit = 1 << (more ? i : maxNumberOfSections - i - 1); - if ( more ) { - newBits |= bit; - } else { - newBits &= ~bit; - } - if ( newBits !== currentBits ) { break; } +dom.on('#gotoReport', 'click', ev => { + if ( ev.isTrusted !== true ) { return; } + let url; + try { + url = new URL(currentTab.url); + } catch { } - if ( newBits === currentBits ) { return; } - sectionBitsToAttribute(newBits); - localWrite('popupPanelSections', newBits); -} + 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}`, + }); +}); -localRead('popupPanelSections').then(bits => { - sectionBitsToAttribute(bits || 0); +/******************************************************************************/ + +dom.on('#gotoDashboard', 'click', ev => { + if ( ev.isTrusted !== true ) { return; } + if ( ev.button !== 0 ) { return; } + runtime.openOptionsPage(); }); -dom.on('#moreButton', 'click', ( ) => { - toggleSections(true); +/******************************************************************************/ + +dom.on('#gotoZapper', 'click', ( ) => { + if ( browser.scripting === undefined ) { return; } + browser.scripting.executeScript({ + files: [ '/js/scripting/tool-overlay.js', '/js/scripting/zapper.js' ], + target: { tabId: currentTab.id }, + }); + self.close(); }); -dom.on('#lessButton', 'click', ( ) => { - toggleSections(false); +/******************************************************************************/ + +dom.on('#gotoPicker', 'click', ( ) => { + if ( browser.scripting === undefined ) { return; } + browser.scripting.executeScript({ + files: [ '/js/scripting/tool-overlay.js', '/js/scripting/picker.js' ], + target: { tabId: currentTab.id }, + }); + self.close(); }); /******************************************************************************/ -dom.on('[data-i18n-title="popupTipDashboard"]', 'click', ev => { - if ( ev.isTrusted !== true ) { return; } - if ( ev.button !== 0 ) { return; } - runtime.openOptionsPage(); +dom.on('#gotoUnpicker', 'click', ( ) => { + if ( browser.scripting === undefined ) { return; } + browser.scripting.executeScript({ + files: [ '/js/scripting/tool-overlay.js', '/js/scripting/unpicker.js' ], + target: { tabId: currentTab.id }, + }); + self.close(); }); /******************************************************************************/ @@ -283,54 +300,45 @@ async function init() { let url; try { + const strictBlockURL = runtime.getURL('/strictblock.'); url = new URL(currentTab.url); - tabHostname = url.hostname || ''; - } catch(ex) { + if ( url.href.startsWith(strictBlockURL) ) { + url = new URL(url.hash.slice(1)); + } + tabURL.href = url.href || ''; + } catch { + return false; } if ( url !== undefined ) { const response = await sendMessage({ what: 'popupPanelData', origin: url.origin, - hostname: normalizedHostname(tabHostname), + normalHostname: normalizedHostname(tabURL.hostname), + hostname: 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)); - const parent = qs$('#rulesetStats'); - for ( const details of popupPanelData.rulesetDetails || [] ) { - const div = dom.clone('#templates .rulesetDetails'); - qs$(div, 'h1').append(i18n.patchUnicodeFlags(details.name)); - const { rules, filters, css } = details; - let ruleCount = rules.plain + rules.regex; - if ( popupPanelData.hasOmnipotence ) { - ruleCount += rules.removeparam + rules.redirect + rules.modifyHeaders; - } - let specificCount = 0; - if ( typeof css.specific === 'number' ) { - specificCount += css.specific; - } - if ( typeof css.declarative === 'number' ) { - specificCount += css.declarative; - } - if ( typeof css.procedural === 'number' ) { - specificCount += css.procedural; - } - dom.text( - qs$(div, 'p'), - i18n$('perRulesetStats') - .replace('{{ruleCount}}', ruleCount.toLocaleString()) - .replace('{{filterCount}}', filters.accepted.toLocaleString()) - .replace('{{cssSpecificCount}}', specificCount.toLocaleString()) - ); - parent.append(div); - } + dom.cl.toggle('#gotoMatchedRules', 'enabled', + popupPanelData.isSideloaded === true && + popupPanelData.developerMode && + typeof currentTab.id === 'number' && + isNaN(currentTab.id) === false + ); + + const isHTTP = url.protocol === 'http:' || url.protocol === 'https:'; + dom.cl.toggle(dom.root, 'isHTTP', isHTTP); + + dom.cl.toggle('#gotoUnpicker', 'enabled', popupPanelData.hasCustomFilters); dom.cl.remove(dom.body, 'loading'); @@ -340,7 +348,7 @@ async function init() { async function tryInit() { try { await init(); - } catch(ex) { + } catch { setTimeout(tryInit, 100); } } diff --git a/platform/mv3/extension/js/report.js b/platform/mv3/extension/js/report.js new file mode 100644 index 0000000000000..3f5f50e07a2f4 --- /dev/null +++ b/platform/mv3/extension/js/report.js @@ -0,0 +1,120 @@ +/******************************************************************************* + + 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 { getTroubleshootingInfo } from './troubleshooting.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 { + } + return null; +})(); + +/******************************************************************************/ + +function reportSpecificFilterType() { + return qs$('select[name="type"]').value; +} + +/******************************************************************************/ + +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 configBody = [ + '```yaml', + qs$('[data-i18n="supportS5H"] + pre').textContent, + '```', + '', + ].join('\n'); + githubURL.searchParams.set('configuration', configBody); + sendMessage({ what: 'gotoURL', url: githubURL.href }); +} + +/******************************************************************************/ + +getTroubleshootingInfo(reportedPage.mode).then(config => { + qs$('[data-i18n="supportS5H"] + pre').textContent = config; + + dom.on('[data-url]', 'click', ev => { + const elem = ev.target.closest('[data-url]'); + const url = dom.attr(elem, 'data-url'); + 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/ro-dnr-editor.js b/platform/mv3/extension/js/ro-dnr-editor.js new file mode 100644 index 0000000000000..795301eb48fd5 --- /dev/null +++ b/platform/mv3/extension/js/ro-dnr-editor.js @@ -0,0 +1,100 @@ +/******************************************************************************* + + 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 { DNREditor } from './dnr-editor.js'; +import { i18n$ } from './i18n.js'; +import { normalizeDNRRules } from './ext-compat.js'; +import { sendMessage } from './ext.js'; +import { textFromRules } from './dnr-parser.js'; + +/******************************************************************************/ + +export class ReadOnlyDNREditor extends DNREditor { + async getText(hint) { + if ( hint === 'dnr.ro.dynamic' ) { + const rules = await sendMessage({ what: 'getEffectiveDynamicRules' }); + if ( Array.isArray(rules) === false ) { return; } + this.id = 'dynamic'; + this.count = rules.length; + return textFromRules(rules, { keepId: true }); + } + if ( hint === 'dnr.ro.session' ) { + const rules = await sendMessage({ what: 'getEffectiveSessionRules' }); + if ( Array.isArray(rules) === false ) { return; } + this.id = 'session'; + this.count = rules.length; + return textFromRules(rules, { keepId: true }); + } + const match = /^dnr\.ro\.(.+)$/.exec(hint); + if ( match === null ) { return; } + this.id = match[1]; + const allRulesetDetails = await sendMessage({ what: 'getRulesetDetails' }); + const rulesetDetails = allRulesetDetails.find(a => a.id === this.id); + if ( rulesetDetails === undefined ) { return; } + const realms = { + plain: 'main', + regex: 'regex', + redirect: 'redirect', + modifyHeaders: 'modify-headers', + removeparam: 'removeparam', + }; + const promises = []; + for ( const [ realm, dir ] of Object.entries(realms) ) { + if ( Boolean(rulesetDetails.rules?.[realm]) === false ) { continue; } + promises.push( + fetch(`./rulesets/${dir}/${this.id}.json`).then(response => + response.json() + ).then(rules => + normalizeDNRRules(rules) + ) + ); + } + const parts = await Promise.all(promises); + const allRules = []; + for ( const rules of parts ) { + for ( const rule of rules ) { + allRules.push(rule); + } + } + this.count = allRules.length; + return textFromRules(allRules, { keepId: true }); + } + + on(editor) { + if ( typeof this.count !== 'number' ) { + return editor.updateSummaryPanel(null); + } + const template = document.querySelector('template.ro-summary-panel'); + const fragment = template.content.cloneNode(true); + const root = fragment.querySelector('.summary-panel'); + root.textContent = i18n$('dnrRulesCountInfo') + .replace('{count}', (this.count || 0).toLocaleString()) + editor.updateSummaryPanel(root); + } + + off(editor) { + editor.updateSummaryPanel(null); + } + + exportToFile(text) { + return super.exportToFile(text, `${this.id}-dnr-ruleset.json`); + } +}; diff --git a/platform/mv3/extension/js/ruleset-manager.js b/platform/mv3/extension/js/ruleset-manager.js index a484e1d21d17d..d1d9eeb425990 100644 --- a/platform/mv3/extension/js/ruleset-manager.js +++ b/platform/mv3/extension/js/ruleset-manager.js @@ -19,28 +19,54 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; +import { + i18n, + localRead, localRemove, localWrite, + runtime, + sessionRead, sessionRemove, sessionWrite, +} from './ext.js'; + +import { + rulesetConfig, + saveRulesetConfig, +} from './config.js'; + +import { dnr } from './ext-compat.js'; +import { fetchJSON } from './fetch.js'; +import { getAdminRulesets } from './admin.js'; +import { hasBroadHostPermissions } from './utils.js'; +import { rulesFromText } from './dnr-parser.js'; +import { ubolLog } from './debug.js'; /******************************************************************************/ -import { browser, dnr, i18n } from './ext.js'; -import { fetchJSON } from './fetch.js'; -import { ubolLog } from './utils.js'; +const SPECIAL_RULES_REALM = 5000000; +const USER_RULES_BASE_RULE_ID = 9000000; +const USER_RULES_PRIORITY = 1000000; +const TRUSTED_DIRECTIVE_BASE_RULE_ID = 8000000; +const TRUSTED_DIRECTIVE_PRIORITY = USER_RULES_PRIORITY + 1000000; +const STRICTBLOCK_PRIORITY = 29; + +let dynamicRegexCount = 0; +let sessionRegexCount = 0; /******************************************************************************/ -const 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 TRUSTED_DIRECTIVE_BASE_RULE_ID = 8000000; +const isStrictBlockRule = rule => { + if ( rule.priority !== STRICTBLOCK_PRIORITY ) { return false; } + if ( rule.condition?.resourceTypes === undefined ) { return false; } + if ( rule.condition.resourceTypes.length !== 1 ) { return false; } + if ( rule.condition.resourceTypes[0] !== 'main_frame' ) { return false; } + if ( rule.action.type === 'redirect' ) { + const substitution = rule.action.redirect.regexSubstitution; + return substitution !== undefined && + substitution.includes('/strictblock.'); + } + if ( rule.action.type === 'allow' ) { + return Array.isArray(rule.condition?.requestDomains); + } + return false; +}; /******************************************************************************/ @@ -59,73 +85,59 @@ 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 - ) - ); +async function pruneInvalidRegexRules(realm, rulesIn, rejected = []) { + const validateRegex = regex => { + return dnr.isRegexSupported({ regex, isCaseSensitive: false }).then(result => { + pruneInvalidRegexRules.validated.set(regex, result?.reason || true); + if ( result.isSupported ) { return true; } + rejected.push({ regex, reason: 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; + const reason = pruneInvalidRegexRules.validated.get(regexFilter); + if ( reason !== undefined ) { + toCheck.push(reason === true); + if ( reason === true ) { continue; } + rejected.push({ regex: regexFilter, reason }); continue; } - toCheck.push( - 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`, - rejectedRegexRules.join('\n') + if ( rejected.length !== 0 ) { + ubolLog(`${realm} realm: rejected regexes:\n`, + rejected.map(e => `${e.regex} → ${e.reason}`).join('\n') ); } return rulesIn.filter((v, i) => isValid[i]); } +pruneInvalidRegexRules.validated = new Map(); /******************************************************************************/ -async function updateRegexRules() { +async function updateRegexRules(currentRules, addRules, removeRuleIds) { + // Remove existing regex-related block rules + for ( const rule of currentRules ) { + if ( rule.id >= SPECIAL_RULES_REALM ) { continue; } + const { type } = rule.action; + if ( type !== 'block' && type !== 'allow' ) { continue; } + if ( rule.condition.regexFilter === undefined ) { continue; } + removeRuleIds.push(rule.id); + } + const rulesetDetails = await getEnabledRulesetsDetails(); // Fetch regexes for all enabled rulesets @@ -138,70 +150,33 @@ 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++; 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 = []; - - 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); - } - } + const validRules = await pruneInvalidRegexRules('regexes', allRules); + if ( validRules.length === 0 ) { return; } - 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`); + addRules.push(...validRules); } /******************************************************************************/ -async function updateRemoveparamRules() { - const [ - hasOmnipotence, - rulesetDetails, - dynamicRuleMap, - ] = await Promise.all([ - browser.permissions.contains({ origins: [ '' ] }), - getEnabledRulesetsDetails(), - getDynamicRules(), - ]); +async function updateRemoveparamRules(currentRules, addRules, removeRuleIds) { + // Remove existing removeparam-related rules + for ( const rule of currentRules ) { + if ( rule.id >= SPECIAL_RULES_REALM ) { continue; } + if ( rule.action.type !== 'redirect' ) { continue; } + if ( rule.action.redirect.transform === undefined ) { continue; } + removeRuleIds.push(rule.id); + } + + const rulesetDetails = await getEnabledRulesetsDetails(); // Fetch removeparam rules for all enabled rulesets const toFetch = []; @@ -211,231 +186,328 @@ async function updateRemoveparamRules() { } const removeparamRulesets = await Promise.all(toFetch); - // 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++; - allRules.push(rule); - } + for ( const rules of removeparamRulesets ) { + if ( Array.isArray(rules) === false ) { continue; } + for ( const rule of rules ) { + allRules.push(rule); } } + if ( allRules.length === 0 ) { return; } - const 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 = []; + ubolLog(`Add ${validRules.length} DNR removeparam rules`); + addRules.push(...validRules); +} - 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); +async function updateRedirectRules(currentRules, addRules, removeRuleIds) { + // Remove existing redirect-related rules + for ( const rule of currentRules ) { + if ( rule.id >= SPECIAL_RULES_REALM ) { continue; } + if ( rule.action.type !== 'redirect' ) { continue; } + if ( rule.action.redirect.extensionPath === undefined ) { continue; } + removeRuleIds.push(rule.id); } - if ( addRules.length === 0 && removeRuleIds.length === 0 ) { return; } + const rulesetDetails = await getEnabledRulesetsDetails(); - if ( removeRuleIds.length !== 0 ) { - ubolLog(`Remove ${removeRuleIds.length} DNR removeparam rules`); + // Fetch redirect rules for all enabled rulesets + const toFetch = []; + for ( const details of rulesetDetails ) { + if ( details.rules.redirect === 0 ) { continue; } + toFetch.push(fetchJSON(`/rulesets/redirect/${details.id}`)); } - if ( addRules.length !== 0 ) { - ubolLog(`Add ${addRules.length} DNR removeparam rules`); + const redirectRulesets = await Promise.all(toFetch); + + const allRules = []; + for ( const rules of redirectRulesets ) { + if ( Array.isArray(rules) === false ) { continue; } + for ( const rule of rules ) { + allRules.push(rule); + } } + if ( allRules.length === 0 ) { return; } - return dnr.updateDynamicRules({ addRules, removeRuleIds }).catch(reason => { - console.error(`updateRemoveparamRules() / ${reason}`); - }); + const validRules = await pruneInvalidRegexRules('redirect', allRules); + if ( validRules.length === 0 ) { return; } + + ubolLog(`Add ${validRules.length} DNR redirect rules`); + addRules.push(...validRules); } /******************************************************************************/ -async function updateRedirectRules() { - const [ - hasOmnipotence, - rulesetDetails, - dynamicRuleMap, - ] = await Promise.all([ - browser.permissions.contains({ origins: [ '' ] }), - getEnabledRulesetsDetails(), - getDynamicRules(), - ]); +async function updateModifyHeadersRules(currentRules, addRules, removeRuleIds) { + // Remove existing header modification-related rules + for ( const rule of currentRules ) { + if ( rule.id >= SPECIAL_RULES_REALM ) { continue; } + if ( rule.action.type !== 'modifyHeaders' ) { continue; } + removeRuleIds.push(rule.id); + } - // Fetch redirect rules for all enabled rulesets + const rulesetDetails = await getEnabledRulesetsDetails(); + + // Fetch modifyHeaders rules for all enabled rulesets const toFetch = []; for ( const details of rulesetDetails ) { - if ( details.rules.redirect === 0 ) { continue; } - toFetch.push(fetchJSON(`/rulesets/redirect/${details.id}`)); + if ( details.rules.modifyHeaders === 0 ) { continue; } + toFetch.push(fetchJSON(`/rulesets/modify-headers/${details.id}`)); } - const redirectRulesets = await Promise.all(toFetch); + const rulesets = await Promise.all(toFetch); - // 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++; - allRules.push(rule); - } + for ( const rules of rulesets ) { + if ( Array.isArray(rules) === false ) { continue; } + for ( const rule of rules ) { + allRules.push(rule); } } + if ( allRules.length === 0 ) { return; } + + const validRules = await pruneInvalidRegexRules('modify-headers', allRules); + if ( validRules.length === 0 ) { return; } - const validatedRules = await pruneInvalidRegexRules('redirect', allRules); + ubolLog(`Add ${validRules.length} DNR modify-headers rules`); + addRules.push(...validRules); +} + +/******************************************************************************/ - // Add redirect rules to dynamic ruleset without affecting rules - // outside redirect rules realm. - const newRuleMap = new Map(validatedRules.map(rule => [ rule.id, rule ])); +async function updateDynamicRules() { + const currentRules = await dnr.getDynamicRules(); 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); + // Remove potentially left-over strict-block rules from previous version + for ( const rule of currentRules ) { + if ( rule.id >= SPECIAL_RULES_REALM ) { continue; } + if ( isStrictBlockRule(rule) === false ) { continue; } + removeRuleIds.push(rule.id); } + await Promise.all([ + updateRegexRules(currentRules, addRules, removeRuleIds), + updateRemoveparamRules(currentRules, addRules, removeRuleIds), + updateRedirectRules(currentRules, addRules, removeRuleIds), + updateModifyHeadersRules(currentRules, addRules, removeRuleIds), + ]); if ( addRules.length === 0 && removeRuleIds.length === 0 ) { return; } - if ( removeRuleIds.length !== 0 ) { - ubolLog(`Remove ${removeRuleIds.length} DNR redirect rules`); + dynamicRegexCount = 0; + let ruleId = 1; + for ( const rule of addRules ) { + if ( rule?.condition.regexFilter ) { dynamicRegexCount += 1; } + rule.id = ruleId++; } - if ( addRules.length !== 0 ) { - ubolLog(`Add ${addRules.length} DNR redirect rules`); + if ( dynamicRegexCount !== 0 ) { + ubolLog(`Using ${dynamicRegexCount}/${dnr.MAX_NUMBER_OF_REGEX_RULES} dynamic regex-based DNR rules`); } + try { + await dnr.updateDynamicRules({ addRules, removeRuleIds }); + if ( removeRuleIds.length !== 0 ) { + ubolLog(`Remove ${removeRuleIds.length} dynamic DNR rules`); + } + if ( addRules.length !== 0 ) { + ubolLog(`Add ${addRules.length} dynamic DNR rules`); + } + } catch(reason) { + console.error(`updateDynamicRules() / ${reason}`); + } + await updateSessionRules(); +} - return dnr.updateDynamicRules({ addRules, removeRuleIds }).catch(reason => { - console.error(`updateRedirectRules() / ${reason}`); - }); +/******************************************************************************/ + +async function getEffectiveDynamicRules() { + const allRules = await dnr.getDynamicRules(); + const dynamicRules = []; + for ( const rule of allRules ) { + if ( rule.id >= USER_RULES_BASE_RULE_ID ) { continue; } + dynamicRules.push(rule); + } + return dynamicRules; } /******************************************************************************/ -async function updateModifyHeadersRules() { +async function updateStrictBlockRules(currentRules, addRules, removeRuleIds) { + // Remove existing strictblock-related rules + for ( const rule of currentRules ) { + if ( isStrictBlockRule(rule) === false ) { continue; } + removeRuleIds.push(rule.id); + } + + if ( rulesetConfig.strictBlockMode === false ) { return; } + const [ hasOmnipotence, rulesetDetails, - dynamicRuleMap, + permanentlyExcluded = [], + temporarilyExcluded = [], ] = await Promise.all([ - browser.permissions.contains({ origins: [ '' ] }), + hasBroadHostPermissions(), getEnabledRulesetsDetails(), - getDynamicRules(), + localRead('excludedStrictBlockHostnames'), + sessionRead('excludedStrictBlockHostnames'), ]); - // Fetch modifyHeaders rules for all enabled rulesets + // Strict-block rules can only be enforced with omnipotence + if ( hasOmnipotence === false ) { + localRemove('excludedStrictBlockHostnames'); + sessionRemove('excludedStrictBlockHostnames'); + return; + } + + // Fetch strick-block rules const toFetch = []; for ( const details of rulesetDetails ) { - if ( details.rules.modifyHeaders === 0 ) { continue; } - toFetch.push(fetchJSON(`/rulesets/modify-headers/${details.id}`)); + if ( details.rules.strictblock === 0 ) { continue; } + toFetch.push(fetchJSON(`/rulesets/strictblock/${details.id}`)); } const rulesets = await Promise.all(toFetch); - // Redirect rules can only be enforced with omnipotence + const substitution = `${runtime.getURL('/strictblock.html')}#\\0`; 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++; - allRules.push(rule); - } + for ( const rules of rulesets ) { + if ( Array.isArray(rules) === false ) { continue; } + for ( const rule of rules ) { + rule.action.redirect.regexSubstitution = substitution; + allRules.push(rule); } } - const validatedRules = await pruneInvalidRegexRules('modify-headers', allRules); + const validRules = await pruneInvalidRegexRules('strictblock', allRules); + if ( validRules.length === 0 ) { return; } + ubolLog(`Add ${validRules.length} DNR strictblock rules`); + for ( const rule of validRules ) { + rule.priority = STRICTBLOCK_PRIORITY; + addRules.push(rule); + } - // 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 = []; + const allExcluded = permanentlyExcluded.concat(temporarilyExcluded); + if ( allExcluded.length === 0 ) { return; } + addRules.unshift({ + action: { type: 'allow' }, + condition: { + requestDomains: allExcluded, + resourceTypes: [ 'main_frame' ], + }, + priority: STRICTBLOCK_PRIORITY, + }); + ubolLog(`Add 1 DNR session rule with ${allExcluded.length} for excluded strict-block domains`); +} - 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 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 updateSessionRules(); +} - for ( const newRule of newRuleMap.values() ) { - if ( dynamicRuleMap.has(newRule.id) ) { continue; } - addRules.push(newRule); - dynamicRuleMap.set(newRule.id, newRule); +async function setStrictBlockMode(state, force = false) { + const newState = Boolean(state); + if ( force === false ) { + 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 updateSessionRules(); +} - if ( addRules.length === 0 && removeRuleIds.length === 0 ) { return; } +/******************************************************************************/ - if ( removeRuleIds.length !== 0 ) { - ubolLog(`Remove ${removeRuleIds.length} DNR modifyHeaders rules`); - } - if ( addRules.length !== 0 ) { - ubolLog(`Add ${addRules.length} DNR modifyHeaders rules`); +async function updateSessionRules() { + const addRulesUnfiltered = []; + const removeRuleIds = []; + const currentRules = await dnr.getSessionRules(); + await updateStrictBlockRules(currentRules, addRulesUnfiltered, removeRuleIds); + if ( addRulesUnfiltered.length === 0 && removeRuleIds.length === 0 ) { return; } + const maxRegexCount = dnr.MAX_NUMBER_OF_REGEX_RULES * 0.80; + let regexCount = dynamicRegexCount; + let ruleId = 1; + for ( const rule of addRulesUnfiltered ) { + if ( rule?.condition.regexFilter ) { regexCount += 1; } + rule.id = regexCount < maxRegexCount ? ruleId++ : 0; + } + sessionRegexCount = regexCount - dynamicRegexCount; + const addRules = addRulesUnfiltered.filter(a => a.id !== 0); + const rejectedRuleCount = addRulesUnfiltered.length - addRules.length; + if ( rejectedRuleCount !== 0 ) { + ubolLog(`Too many regex-based filters, ${rejectedRuleCount} session rules dropped`); + } + if ( sessionRegexCount !== 0 ) { + ubolLog(`Using ${sessionRegexCount}/${dnr.MAX_NUMBER_OF_REGEX_RULES} session regex-based DNR rules`); + } + try { + await dnr.updateSessionRules({ addRules, removeRuleIds }); + if ( removeRuleIds.length !== 0 ) { + ubolLog(`Remove ${removeRuleIds.length} session DNR rules`); + } + if ( addRules.length !== 0 ) { + ubolLog(`Add ${addRules.length} session DNR rules`); + } + } catch(reason) { + console.error(`updateSessionRules() / ${reason}`); } - - return dnr.updateDynamicRules({ addRules, removeRuleIds }).catch(reason => { - console.error(`updateModifyHeadersRules() / ${reason}`); - }); } /******************************************************************************/ -// TODO: group all omnipotence-related rules into one realm. - -async function updateDynamicRules() { - return Promise.all([ - updateRegexRules(), - updateRemoveparamRules(), - updateRedirectRules(), - updateModifyHeadersRules(), - ]); +async function getEffectiveSessionRules() { + const allRules = await dnr.getSessionRules(); + const sessionRules = []; + for ( const rule of allRules ) { + if ( rule.id >= USER_RULES_BASE_RULE_ID ) { continue; } + sessionRules.push(rule); + } + return sessionRules; } /******************************************************************************/ -async function defaultRulesetsFromLanguage() { - const out = [ 'default' ]; +async function filteringModesToDNR(modes) { + const noneHostnames = new Set([ ...modes.none ]); + const notNoneHostnames = new Set([ ...modes.basic, ...modes.optimal, ...modes.complete ]); + const requestDomains = []; + const excludedRequestDomains = []; + const allowEverywhere = noneHostnames.has('all-urls'); + if ( allowEverywhere ) { + excludedRequestDomains.push(...notNoneHostnames); + } else { + requestDomains.push(...noneHostnames); + } + const noneCount = allowEverywhere + ? notNoneHostnames.size + : noneHostnames.size; + return dnr.setAllowAllRules( + TRUSTED_DIRECTIVE_BASE_RULE_ID, + requestDomains.sort(), + excludedRequestDomains.sort(), + allowEverywhere, + TRUSTED_DIRECTIVE_PRIORITY + ).then(modified => { + if ( modified === false ) { return; } + ubolLog(`${allowEverywhere ? 'Enabled' : 'Disabled'} DNR filtering for ${noneCount} sites`); + }); +} +/******************************************************************************/ + +async function defaultRulesetsFromEnv() { const dropCountry = lang => { const pos = lang.indexOf('-'); if ( pos === -1 ) { return lang; } @@ -453,20 +525,95 @@ async function defaultRulesetsFromLanguage() { `\\b(${Array.from(langSet).join('|')})\\b` ); + const reMobile = /\bMobile\b/.test(navigator.userAgent) + ? /\bmobile\b/ + : null + const rulesetDetails = await getRulesetDetails(); - for ( const [ id, details ] of rulesetDetails ) { - if ( typeof details.lang !== 'string' ) { continue; } - if ( reTargetLang.test(details.lang) === false ) { continue; } - out.push(id); + const out = []; + for ( const ruleset of rulesetDetails.values() ) { + const { id, enabled } = ruleset; + if ( enabled ) { + out.push(id); + continue; + } + if ( typeof ruleset.lang === 'string' ) { + if ( reTargetLang.test(ruleset.lang) ) { + out.push(id); + continue; + } + } + if ( typeof ruleset.tags === 'string' ) { + if ( reMobile?.test(ruleset.tags) ) { + out.push(id); + continue; + } + } } + return out; } /******************************************************************************/ +async function patchDefaultRulesets() { + const [ + oldDefaultIds = [], + newDefaultIds, + staticRulesetIds, + ] = await Promise.all([ + localRead('defaultRulesetIds'), + defaultRulesetsFromEnv(), + getStaticRulesets().then(r => r.map(a => a.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 ( staticRulesetIds.includes(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 +625,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 +635,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); @@ -502,9 +649,27 @@ async function enableRulesets(ids) { if ( disableRulesetIds.length !== 0 ) { ubolLog(`Disable ruleset: ${disableRulesetIds}`); } - await dnr.updateEnabledRulesets({ enableRulesetIds, disableRulesetIds }); - - return updateDynamicRules(); + await dnr.updateEnabledRulesets({ enableRulesetIds, disableRulesetIds }).catch(reason => { + ubolLog(reason); + }); + + await updateDynamicRules(); + + dnr.getEnabledRulesets().then(enabledRulesets => { + ubolLog(`Enabled rulesets: ${enabledRulesets}`); + return dnr.getAvailableStaticRuleCount(); + }).then(count => { + ubolLog(`Available static rule count: ${count}`); + }); + + return true; +} + +/******************************************************************************/ + +async function getStaticRulesets() { + const manifest = runtime.getManifest(); + return manifest.declarative_net_request.rule_resources; } /******************************************************************************/ @@ -528,12 +693,96 @@ async function getEnabledRulesetsDetails() { /******************************************************************************/ +async function getEffectiveUserRules() { + const allRules = await dnr.getDynamicRules(); + const userRules = []; + for ( const rule of allRules ) { + if ( rule.id < USER_RULES_BASE_RULE_ID ) { continue; } + userRules.push(rule); + } + return userRules; +} + +async function updateUserRules() { + const [ + userRules, + userRulesText = '', + ] = await Promise.all([ + getEffectiveUserRules(), + localRead('userDnrRules'), + ]); + + const effectiveRulesText = rulesetConfig.developerMode + ? userRulesText + : ''; + + const parsed = rulesFromText(effectiveRulesText); + const { rules } = parsed; + const removeRuleIds = [ ...userRules.map(a => a.id) ]; + const rejectedRegexes = []; + const addRules = await pruneInvalidRegexRules('user', rules, rejectedRegexes); + const out = { added: 0, removed: 0, errors: [] }; + + if ( rejectedRegexes.length !== 0 ) { + rejectedRegexes.forEach(e => + out.errors.push(`regexFilter: ${e.regex} → ${e.reason}`) + ); + } + + if ( removeRuleIds.length === 0 && addRules.length === 0 ) { + await localRemove('userDnrRuleCount'); + return out; + } + + let ruleId = 0; + for ( const rule of addRules ) { + rule.id = USER_RULES_BASE_RULE_ID + ruleId++; + rule.priority = (rule.priority || 1) + USER_RULES_PRIORITY; + } + + // Rules are first removed separately to ensure registered rules match + // user rules text. A bad rule in user rules text would prevent the + // rules from being removed if the removal was done at the same time as + // adding rules. + try { + await dnr.updateDynamicRules({ removeRuleIds }); + await dnr.updateDynamicRules({ addRules }); + if ( removeRuleIds.length !== 0 ) { + ubolLog(`updateUserRules() / Removed ${removeRuleIds.length} dynamic DNR rules`); + } + if ( addRules.length !== 0 ) { + ubolLog(`updateUserRules() / Added ${addRules.length} DNR rules`); + } + out.added = addRules.length; + out.removed = removeRuleIds.length; + } catch(reason) { + console.info(`updateUserRules() / ${reason}`); + out.errors.push(`${reason}`); + } finally { + const userRules = await getEffectiveUserRules(); + if ( userRules.length === 0 ) { + await localRemove('userDnrRuleCount'); + } else { + await localWrite('userDnrRuleCount', addRules.length); + } + } + return out; +} + +/******************************************************************************/ + export { - TRUSTED_DIRECTIVE_BASE_RULE_ID, - getRulesetDetails, - getDynamicRules, enableRulesets, - defaultRulesetsFromLanguage, + excludeFromStrictBlock, + filteringModesToDNR, + getEffectiveDynamicRules, + getEffectiveSessionRules, + getEffectiveUserRules, getEnabledRulesetsDetails, + getRulesetDetails, + patchDefaultRulesets, + setStrictBlockMode, updateDynamicRules, + updateSessionRules, + updateUserRules, }; diff --git a/platform/mv3/extension/js/rw-dnr-editor.js b/platform/mv3/extension/js/rw-dnr-editor.js new file mode 100644 index 0000000000000..05a56c1f44b2d --- /dev/null +++ b/platform/mv3/extension/js/rw-dnr-editor.js @@ -0,0 +1,405 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2014-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { + browser, + localRead, + localRemove, + localWrite, + sendMessage, +} from './ext.js'; +import { dom, qs$ } from './dom.js'; +import { i18n, i18n$ } from './i18n.js'; +import { DNREditor } from './dnr-editor.js'; +import { parseFilters } from './ubo-parser.js'; +import { textFromRules } from './dnr-parser.js'; + +/******************************************************************************/ + +export class ReadWriteDNREditor extends DNREditor { + constructor(editor) { + super(); + this.feedbackPanel = self.cm6.createViewPanel(); + editor.panels.push(this.feedbackPanel); + } + + async getText() { + return localRead('userDnrRules'); + } + + on(editor) { + localRead('userDnrRuleCount').then(userDnrRuleCount => { + this.updateSummaryPanel(editor, { userDnrRuleCount }) + }); + browser.storage.onChanged.addListener((changes, area) => { + if ( area !== 'local' ) { return; } + const { userDnrRuleCount } = changes; + if ( userDnrRuleCount instanceof Object === false ) { return; } + const { newValue } = changes.userDnrRuleCount; + this.updateSummaryPanel(editor, { userDnrRuleCount: newValue }); + }); + } + + off(editor) { + this.updateSummaryPanel(editor, null); + this.updateFeedbackPanel(editor, null); + } + + rulesFromJSON(json) { + let content = json.trim(); + if ( /^[[{]/.test(content) === false ) { + const match = /^[^[{]+/.exec(content); + if ( match === null ) { return; } + content = content.slice(match[0].length); + } + const firstChar = content.charAt(0); + const expectedLastChar = firstChar === '[' ? ']' : '}'; + if ( content.at(-1) !== expectedLastChar ) { + const re = new RegExp(`\\${expectedLastChar}[^\\${expectedLastChar}]+$`); + const match = re.exec(content); + if ( match === null ) { return; } + content = content.slice(0, match.index+1); + } + if ( content.startsWith('{') && content.endsWith('}') ) { + content = `[${content}]`; + } + try { + const rules = JSON.parse(content); + if ( Array.isArray(rules) ) { return rules; } + } + catch { + } + } + + getAutocompleteCandidates(editor, from) { + const { scope } = editor.getScopeAt(from); + switch ( scope ) { + case '': + return { + before: /^$/, + candidates: [ + { token: 'action:', after: '\n' }, + { token: 'condition:', after: '\n ' }, + { token: 'priority:', after: ' ' }, + { token: '---', after: '\n' }, + ] + }; + case 'action:': + return { + before: /^ {2}$/, + candidates: [ + { token: 'type:', after: ' ' }, + { token: 'redirect:', after: '\n ' }, + { token: 'requestHeaders:', after: '\n - header: ' }, + { token: 'responseHeaders:', after: '\n - header: ' }, + ], + }; + case 'action:type:': + return { + before: /: $/, + candidates: [ + { token: 'block', after: '\n ' }, + { token: 'redirect', after: '\n ' }, + { token: 'allow', after: '\n ' }, + { token: 'modifyHeaders', after: '\n ' }, + { token: 'upgradeScheme', after: '\n ' }, + { token: 'allowAllRequest', after: '\n ' }, + ], + }; + case 'action:redirect:': + return { + before: /^ {4}$/, + candidates: [ + { token: 'extensionPath:', after: ' ' }, + { token: 'regexSubstitution:', after: ' ' }, + { token: 'transform:', after: '\n ' }, + { token: 'url:', after: ' ' }, + ], + }; + case 'action:redirect:transform:': + return { + before: /^ {6}$/, + candidates: [ + { token: 'fragment:', after: ' ' }, + { token: 'host:', after: ' ' }, + { token: 'path:', after: ' ' }, + { token: 'port:', after: ' ' }, + { token: 'query:', after: ' ' }, + { token: 'scheme:', after: ' ' }, + { token: 'queryTransform:', after: '\n ' }, + ], + }; + case 'action:redirect:transform:queryTransform:': + return { + before: /^ {8}$/, + candidates: [ + { token: 'addOrReplaceParams:', after: '\n - ' }, + { token: 'removeParams:', after: '\n - ' }, + ], + }; + case 'action:responseHeaders:': + case 'action:requestHeaders:': + return { + before: /^ {4}- $/, + candidates: [ + { token: 'header:', after: ' ' }, + ], + }; + case 'action:responseHeaders:header:': + case 'action:requestHeaders:header:': + return { + before: /^ {6}$/, + candidates: [ + { token: 'operation:', after: ' ' }, + { token: 'value:', after: ' ' }, + ], + }; + case 'action:responseHeaders:header:operation:': + case 'action:requestHeaders:header:operation:': + return { + before: /: $/, + candidates: [ + { token: 'append', after: '\n value: ' }, + { token: 'set', after: '\n value: ' }, + { token: 'remove', after: '\n ' }, + ], + }; + case 'condition:': + return { + before: /^ {2}$/, + candidates: [ + { token: 'domainType:', after: ' ' }, + { token: 'isUrlFilterCaseSensitive:', after: ' ' }, + { token: 'regexFilter:', after: ' ' }, + { token: 'urlFilter:', after: ' ' }, + { token: 'initiatorDomains:', after: '\n - ' }, + { token: 'excludedInitiatorDomains:', after: '\n - ' }, + { token: 'requestDomains:', after: '\n - ' }, + { token: 'excludedRequestDomains:', after: '\n - ' }, + { token: 'resourceTypes:', after: '\n - ' }, + { token: 'excludedResourceTypes:', after: '\n - ' }, + { token: 'requestMethods:', after: '\n - ' }, + { token: 'excludedRequestMethods:', after: '\n - ' }, + { token: 'responseHeaders:', after: '\n - ' }, + { token: 'excludedResponseHeaders:', after: '\n - ' }, + ], + }; + case 'condition:domainType:': + return { + before: /: $/, + candidates: [ + { token: 'firstParty', after: '\n ' }, + { token: 'thirdParty', after: '\n ' }, + ], + }; + case 'condition:isUrlFilterCaseSensitive:': + return { + before: /: $/, + candidates: [ + { token: 'true', after: '\n ' }, + { token: 'false', after: '\n ' }, + ], + }; + case 'condition:requestMethods:': + case 'condition:excludedRequestMethods:': + return { + before: /^ {4}- $/, + candidates: [ + { token: 'connect', after: '\n - ' }, + { token: 'delete', after: '\n - ' }, + { token: 'get', after: '\n - ' }, + { token: 'head', after: '\n - ' }, + { token: 'options', after: '\n - ' }, + { token: 'patch', after: '\n - ' }, + { token: 'post', after: '\n - ' }, + { token: 'put', after: '\n - ' }, + { token: 'other', after: '\n ' }, + ], + }; + case 'condition:resourceTypes:': + case 'condition:excludedResourceTypes:': + return { + before: /^ {4}- $/, + candidates: [ + { token: 'main_frame', after: '\n - ' }, + { token: 'sub_frame', after: '\n - ' }, + { token: 'stylesheet', after: '\n - ' }, + { token: 'script', after: '\n - ' }, + { token: 'image', after: '\n - ' }, + { token: 'font', after: '\n - ' }, + { token: 'object', after: '\n - ' }, + { token: 'xmlhttprequest', after: '\n - ' }, + { token: 'ping', after: '\n - ' }, + { token: 'csp_report', after: '\n - ' }, + { token: 'media', after: '\n - ' }, + { token: 'websocket', after: '\n - ' }, + { token: 'webtransport', after: '\n - ' }, + { token: 'webbundle', after: '\n - ' }, + { token: 'other', after: '\n ' }, + ], + }; + } + } + + autoComplete(editor, context) { + const match = context.matchBefore(/[\w-]*/); + if ( match === undefined ) { return null; } + const result = this.getAutocompleteCandidates(editor, match.from); + if ( result === undefined ) { return null; } + if ( result.before !== undefined ) { + const { doc } = context.state; + const line = doc.lineAt(context.pos); + const before = doc.sliceString(line.from, match.from); + if ( result.before.test(before) === false ) { return null; } + } + const filtered = result.candidates.filter(e => + e.token !== match.text || e.after !== '\n' + ); + return { + from: match.from, + options: filtered.map(e => ({ label: e.token, apply: `${e.token}${e.after}` })), + validFor: /\w*/, + }; + } + + async saveEditorText(editor) { + const text = editor.getEditorText().trim(); + await (text.length !== 0 + ? localWrite('userDnrRules', text) + : localRemove('userDnrRules') + ); + const response = await sendMessage({ what: 'updateUserDnrRules' }) + if ( response instanceof Object ) { + this.updateFeedbackPanel(editor, response); + } + return true; + } + + updateSummaryPanel(editor, details) { + if ( details instanceof Object === false ) { + return editor.updateSummaryPanel(null); + } + const template = document.querySelector('template.summary-panel'); + const fragment = template.content.cloneNode(true); + const root = fragment.querySelector('.summary-panel'); + i18n.render(root); + const info = root.querySelector('.info'); + info.textContent = i18n$('dnrRulesCountInfo') + .replace('{count}', (details.userDnrRuleCount || 0).toLocaleString()) + editor.updateSummaryPanel(root); + } + + updateFeedbackPanel(editor, details) { + if ( details instanceof Object === false ) { + return this.feedbackPanel.render(editor.view, null); + } + const errors = []; + if ( Array.isArray(details.errors) ) { + details.errors.forEach(e => errors.push(e)); + } + const text = errors.join('\n'); + const config = (( ) => { + if ( text === '' ) { return null; } + const template = document.querySelector('template.feedback-panel'); + const fragment = template.content.cloneNode(true); + const root = fragment.querySelector('.feedback-panel'); + const info = root.querySelector('.info'); + info.textContent = text; + const closeFn = this.updateFeedbackPanel.bind(this, editor, null); + return { + dom: root, + mount() { + dom.on(qs$('.feedback-panel .close'), 'click', closeFn); + } + }; + })(); + this.feedbackPanel.render(editor.view, config); + } + + importFromFile(editor, json) { + const rules = this.rulesFromJSON(json); + if ( rules === undefined ) { return; } + const text = textFromRules(rules); + if ( text === undefined ) { return; } + const { doc } = editor.view.state; + const lastChars = doc.toString().trimEnd().slice(-4); + const lastLine = doc.line(doc.lines); + let from = lastLine.to; + let prepend = ''; + if ( lastLine.text !== '' ) { + prepend = '\n'; + } else { + from = lastLine.from; + } + if ( /(?:^|\n)---$/.test(lastChars) === false ) { + prepend = `${prepend}---\n`; + } + editor.view.dispatch({ changes: { from, insert: `${prepend}${text}` } }); + self.cm6.foldAll(editor.view); + editor.view.focus(); + } + + exportToFile(text) { + return super.exportToFile(text, 'my-ubol-dnr-rules.json'); + } + + importFromPaste(editor, transaction) { + const { from, to } = editor.rangeFromTransaction(transaction); + if ( from === undefined || to === undefined ) { return; } + // Paste position must match start of a line + const { newDoc } = transaction; + const lineFrom = newDoc.lineAt(from); + if ( lineFrom.from !== from ) { return; } + // Paste position must match a rule boundary + let separatorBefore = false; + if ( lineFrom.number !== 1 ) { + const lineBefore = newDoc.line(lineFrom.number-1); + if ( /^---\s*$/.test(lineBefore.text) === false ) { return; } + separatorBefore = true; + } + const pastedText = newDoc.sliceString(from, to); + let prepend; + let rules = this.rulesFromJSON(pastedText); + if ( Boolean(rules?.length) === false ) { + rules = parseFilters(pastedText); + if ( Boolean(rules?.length) === false ) { return; } + prepend = pastedText.trim().split(/\n/).map(a => `# ${a}`).join('\n'); + } + let yamlText = textFromRules(rules); + if ( yamlText === undefined ) { return; } + if ( prepend ) { + yamlText = yamlText.replace('---\n', `---\n${prepend}\n`); + } + if ( separatorBefore && yamlText.startsWith('---\n') ) { + yamlText = yamlText.slice(4); + } + editor.view.dispatch({ changes: { from, to, insert: yamlText } }); + self.cm6.foldAll(editor.view); + return true; + } + + newlineAssistant = { + 'action:': ' type: ', + 'action:responseHeaders:header:': ' operation: ', + }; + + ioAccept = '.json,application/json'; +}; diff --git a/platform/mv3/extension/js/scripting-manager.js b/platform/mv3/extension/js/scripting-manager.js index e6eebf29f7b9b..17bd5ac8d4a25 100644 --- a/platform/mv3/extension/js/scripting-manager.js +++ b/platform/mv3/extension/js/scripting-manager.js @@ -19,23 +19,23 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; +import * as ut from './utils.js'; -/******************************************************************************/ +import { + browser, + localRemove, + localWrite, +} from './ext.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 { registerCustomFilters } from './filter-manager.js'; +import { registerToolbarIconToggler } from './action.js'; +import { ubolLog } from './debug.js'; /******************************************************************************/ -const isGecko = browser.runtime.getURL('').startsWith('moz-extension://'); - const resourceDetailPromises = new Map(); function getScriptletDetails() { @@ -60,15 +60,13 @@ function getGenericDetails() { /******************************************************************************/ -// Important: We need to sort the arrays for fast comparison -const arrayEq = (a = [], b = [], sort = true) => { - const alen = a.length; - if ( alen !== b.length ) { return false; } - if ( sort ) { a.sort(); b.sort(); } - for ( let i = 0; i < alen; i++ ) { - if ( a[i] !== b[i] ) { return false; } +const normalizeMatches = matches => { + if ( matches.length <= 1 ) { return; } + if ( matches.includes('') === false ) { + if ( matches.includes('*://*/*') === false ) { return; } } - return true; + matches.length = 0; + matches.push(''); }; /******************************************************************************/ @@ -100,11 +98,17 @@ function registerHighGeneric(context, genericDetails) { const { before, filteringModeDetails, rulesetsDetails } = context; const excludeHostnames = []; + const includeHostnames = []; const css = []; for ( const details of rulesetsDetails ) { const hostnames = genericDetails.get(details.id); - if ( hostnames !== undefined ) { - excludeHostnames.push(...hostnames); + if ( hostnames ) { + if ( hostnames.unhide ) { + excludeHostnames.push(...hostnames.unhide); + } + if ( hostnames.hide ) { + includeHostnames.push(...hostnames.hide); + } } const count = details.css?.generichigh || 0; if ( count === 0 ) { continue; } @@ -145,9 +149,12 @@ function registerHighGeneric(context, genericDetails) { id: 'css-generichigh', css, matches, - excludeMatches, + allFrames: true, runAt: 'document_end', }; + if ( excludeMatches.length !== 0 ) { + directive.excludeMatches = excludeMatches; + } // register if ( registered === undefined ) { @@ -157,9 +164,9 @@ function registerHighGeneric(context, genericDetails) { // update if ( - arrayEq(registered.css, css, false) === false || - arrayEq(registered.matches, matches) === false || - arrayEq(registered.excludeMatches, excludeMatches) === false + ut.strArrayEq(registered.css, css, false) === false || + ut.strArrayEq(registered.matches, matches) === false || + ut.strArrayEq(registered.excludeMatches, excludeMatches) === false ) { context.toRemove.push('css-generichigh'); context.toAdd.push(directive); @@ -171,12 +178,18 @@ function registerHighGeneric(context, genericDetails) { function registerGeneric(context, genericDetails) { const { before, filteringModeDetails, rulesetsDetails } = context; - const excludeHostnames = []; + const excludedByFilter = []; + const includedByFilter = []; const js = []; for ( const details of rulesetsDetails ) { const hostnames = genericDetails.get(details.id); - if ( hostnames !== undefined ) { - excludeHostnames.push(...hostnames); + if ( hostnames ) { + if ( hostnames.unhide ) { + excludedByFilter.push(...hostnames.unhide); + } + if ( hostnames.hide ) { + includedByFilter.push(...hostnames.hide); + } } const count = details.css?.generic || 0; if ( count === 0 ) { continue; } @@ -185,55 +198,93 @@ function registerGeneric(context, genericDetails) { if ( js.length === 0 ) { return; } + js.unshift('/js/scripting/isolated-api.js'); js.push('/js/scripting/css-generic.js'); const { none, basic, optimal, complete } = filteringModeDetails; - const matches = []; - const excludeMatches = []; - if ( complete.has('all-urls') ) { - excludeMatches.push(...ut.matchesFromHostnames(none)); - excludeMatches.push(...ut.matchesFromHostnames(basic)); - excludeMatches.push(...ut.matchesFromHostnames(optimal)); - excludeMatches.push(...ut.matchesFromHostnames(excludeHostnames)); - matches.push(''); - } else { - matches.push( + const includedByMode = [ ...complete ]; + const excludedByMode = [ ...none, ...basic, ...optimal ]; + + if ( complete.has('all-urls') === false ) { + const matches = [ ...ut.matchesFromHostnames( - ut.subtractHostnameIters( - Array.from(complete), - excludeHostnames - ) - ) - ); + ut.subtractHostnameIters(includedByMode, excludedByFilter) + ), + ...ut.matchesFromHostnames( + ut.intersectHostnameIters(includedByMode, includedByFilter) + ), + ]; + if ( matches.length === 0 ) { return; } + const registered = before.get('css-generic-some'); + before.delete('css-generic-some'); // Important! + const directive = { + id: 'css-generic-some', + js, + allFrames: true, + matches, + runAt: 'document_idle', + }; + if ( registered === undefined ) { // register + context.toAdd.push(directive); + } else if ( // update + ut.strArrayEq(registered.js, js, false) === false || + ut.strArrayEq(registered.matches, directive.matches) === false + ) { + context.toRemove.push('css-generic-some'); + context.toAdd.push(directive); + } + return; } - if ( matches.length === 0 ) { return; } - - const registered = before.get('css-generic'); - before.delete('css-generic'); // Important! - - const directive = { - id: 'css-generic', + const excludeMatches = [ + ...ut.matchesFromHostnames(excludedByMode), + ...ut.matchesFromHostnames(excludedByFilter), + ]; + const registeredAll = before.get('css-generic-all'); + before.delete('css-generic-all'); // Important! + const directiveAll = { + id: 'css-generic-all', js, - matches, - excludeMatches, + allFrames: true, + matches: [ '' ], runAt: 'document_idle', }; - - // register - if ( registered === undefined ) { - context.toAdd.push(directive); - return; + if ( excludeMatches.length !== 0 ) { + directiveAll.excludeMatches = excludeMatches; } - // update - if ( - arrayEq(registered.js, js, false) === false || - arrayEq(registered.matches, matches) === false || - arrayEq(registered.excludeMatches, excludeMatches) === false + if ( registeredAll === undefined ) { // register + context.toAdd.push(directiveAll); + } else if ( // update + ut.strArrayEq(registeredAll.js, js, false) === false || + ut.strArrayEq(registeredAll.excludeMatches, directiveAll.excludeMatches) === false ) { - context.toRemove.push('css-generic'); - context.toAdd.push(directive); + context.toRemove.push('css-generic-all'); + context.toAdd.push(directiveAll); + } + const matches = [ + ...ut.matchesFromHostnames( + ut.subtractHostnameIters(includedByFilter, excludedByMode) + ), + ]; + if ( matches.length === 0 ) { return; } + const registeredSome = before.get('css-generic-some'); + before.delete('css-generic-some'); // Important! + const directiveSome = { + id: 'css-generic-some', + js, + allFrames: true, + matches, + runAt: 'document_idle', + }; + if ( registeredSome === undefined ) { // register + context.toAdd.push(directiveSome); + } else if ( // update + ut.strArrayEq(registeredSome.js, js, false) === false || + ut.strArrayEq(registeredSome.matches, directiveSome.matches) === false + ) { + context.toRemove.push('css-generic-some'); + context.toAdd.push(directiveSome); } } @@ -257,6 +308,9 @@ function registerProcedural(context) { ]; if ( matches.length === 0 ) { return; } + normalizeMatches(matches); + + js.unshift('/js/scripting/isolated-api.js'); js.push('/js/scripting/css-procedural.js'); const excludeMatches = []; @@ -273,11 +327,13 @@ function registerProcedural(context) { const directive = { id: 'css-procedural', js, - allFrames: true, matches, - excludeMatches, - runAt: 'document_end', + allFrames: true, + runAt: 'document_start', }; + if ( excludeMatches.length !== 0 ) { + directive.excludeMatches = excludeMatches; + } // register if ( registered === undefined ) { @@ -287,9 +343,9 @@ function registerProcedural(context) { // update if ( - arrayEq(registered.js, js, false) === false || - arrayEq(registered.matches, matches) === false || - arrayEq(registered.excludeMatches, excludeMatches) === false + ut.strArrayEq(registered.js, js, false) === false || + ut.strArrayEq(registered.matches, matches) === false || + ut.strArrayEq(registered.excludeMatches, excludeMatches) === false ) { context.toRemove.push('css-procedural'); context.toAdd.push(directive); @@ -316,6 +372,9 @@ function registerDeclarative(context) { ]; if ( matches.length === 0 ) { return; } + normalizeMatches(matches); + + js.unshift('/js/scripting/isolated-api.js'); js.push('/js/scripting/css-declarative.js'); const excludeMatches = []; @@ -332,11 +391,13 @@ function registerDeclarative(context) { const directive = { id: 'css-declarative', js, - allFrames: true, matches, - excludeMatches, + allFrames: true, runAt: 'document_start', }; + if ( excludeMatches.length !== 0 ) { + directive.excludeMatches = excludeMatches; + } // register if ( registered === undefined ) { @@ -346,9 +407,9 @@ function registerDeclarative(context) { // update if ( - arrayEq(registered.js, js, false) === false || - arrayEq(registered.matches, matches) === false || - arrayEq(registered.excludeMatches, excludeMatches) === false + ut.strArrayEq(registered.js, js, false) === false || + ut.strArrayEq(registered.matches, matches) === false || + ut.strArrayEq(registered.excludeMatches, excludeMatches) === false ) { context.toRemove.push('css-declarative'); context.toAdd.push(directive); @@ -375,6 +436,9 @@ function registerSpecific(context) { ]; if ( matches.length === 0 ) { return; } + normalizeMatches(matches); + + js.unshift('/js/scripting/isolated-api.js'); js.push('/js/scripting/css-specific.js'); const excludeMatches = []; @@ -391,11 +455,13 @@ function registerSpecific(context) { const directive = { id: 'css-specific', js, - allFrames: true, matches, - excludeMatches, + allFrames: true, runAt: 'document_start', }; + if ( excludeMatches.length !== 0 ) { + directive.excludeMatches = excludeMatches; + } // register if ( registered === undefined ) { @@ -405,9 +471,9 @@ function registerSpecific(context) { // update if ( - arrayEq(registered.js, js, false) === false || - arrayEq(registered.matches, matches) === false || - arrayEq(registered.excludeMatches, excludeMatches) === false + ut.strArrayEq(registered.js, js, false) === false || + ut.strArrayEq(registered.matches, matches) === false || + ut.strArrayEq(registered.excludeMatches, excludeMatches) === false ) { context.toRemove.push('css-specific'); context.toAdd.push(directive); @@ -436,7 +502,7 @@ function registerScriptlet(context, scriptletDetails) { const scriptletList = scriptletDetails.get(rulesetId); if ( scriptletList === undefined ) { continue; } - for ( const [ token, scriptletHostnames ] of scriptletList ) { + for ( const [ token, details ] of scriptletList ) { const id = `${rulesetId}.${token}`; const registered = before.get(id); @@ -445,39 +511,38 @@ function registerScriptlet(context, scriptletDetails) { let targetHostnames = []; if ( hasBroadHostPermission ) { excludeMatches.push(...permissionRevokedMatches); - if ( scriptletHostnames.length > 100 ) { + if ( details.hostnames.length > 100 ) { targetHostnames = [ '*' ]; } else { - targetHostnames = scriptletHostnames; + targetHostnames = details.hostnames; } } else if ( permissionGrantedHostnames.length !== 0 ) { - if ( scriptletHostnames.includes('*') ) { + if ( details.hostnames.includes('*') ) { targetHostnames = permissionGrantedHostnames; } else { targetHostnames = ut.intersectHostnameIters( - permissionGrantedHostnames, - scriptletHostnames + details.hostnames, + permissionGrantedHostnames ); } } if ( targetHostnames.length === 0 ) { continue; } matches.push(...ut.matchesFromHostnames(targetHostnames)); + normalizeMatches(matches); before.delete(id); // Important! const directive = { id, js: [ `/rulesets/scripting/scriptlet/${id}.js` ], - allFrames: true, matches, - excludeMatches, + allFrames: true, + matchOriginAsFallback: true, runAt: 'document_start', + world: details.world, }; - - // https://bugzilla.mozilla.org/show_bug.cgi?id=1736575 - // `MAIN` world not yet supported in Firefox - if ( isGecko === false ) { - directive.world = 'MAIN'; + if ( excludeMatches.length !== 0 ) { + directive.excludeMatches = excludeMatches; } // register @@ -488,8 +553,8 @@ function registerScriptlet(context, scriptletDetails) { // update if ( - arrayEq(registered.matches, matches) === false || - arrayEq(registered.excludeMatches, excludeMatches) === false + ut.strArrayEq(registered.matches, matches) === false || + ut.strArrayEq(registered.excludeMatches, excludeMatches) === false ) { context.toRemove.push(id); context.toAdd.push(directive); @@ -500,11 +565,15 @@ function registerScriptlet(context, scriptletDetails) { /******************************************************************************/ -async function registerInjectables(origins) { - void origins; +// Issue: Safari appears to completely ignore excludeMatches +// https://github.com/radiolondra/ExcludeMatches-Test +async function registerInjectables() { if ( browser.scripting === undefined ) { return false; } + if ( registerInjectables.barrier ) { return true; } + registerInjectables.barrier = true; + const [ filteringModeDetails, rulesetsDetails, @@ -532,27 +601,43 @@ async function registerInjectables(origins) { toRemove, }; - registerDeclarative(context); - registerProcedural(context); - registerScriptlet(context, scriptletDetails); - registerSpecific(context); - registerGeneric(context, genericDetails); - registerHighGeneric(context, genericDetails); + await Promise.all([ + registerDeclarative(context), + registerProcedural(context), + registerScriptlet(context, scriptletDetails), + registerSpecific(context), + registerGeneric(context, genericDetails), + registerHighGeneric(context, genericDetails), + registerCustomFilters(context), + registerToolbarIconToggler(context), + ]); toRemove.push(...Array.from(before.keys())); if ( toRemove.length !== 0 ) { - ut.ubolLog(`Unregistered ${toRemove} content (css/js)`); - await browser.scripting.unregisterContentScripts({ ids: toRemove }) - .catch(reason => { console.info(reason); }); + ubolLog(`Unregistered ${toRemove} content (css/js)`); + try { + await browser.scripting.unregisterContentScripts({ ids: toRemove }); + localRemove('$scripting.unregisterContentScripts'); + } catch(reason) { + localWrite('$scripting.unregisterContentScripts', `${reason}`); + console.info(reason); + } } if ( toAdd.length !== 0 ) { - ut.ubolLog(`Registered ${toAdd.map(v => v.id)} content (css/js)`); - await browser.scripting.registerContentScripts(toAdd) - .catch(reason => { console.info(reason); }); + ubolLog(`Registered ${toAdd.map(v => v.id)} content (css/js)`); + try { + await browser.scripting.registerContentScripts(toAdd); + localRemove('$scripting.registerContentScripts'); + } catch(reason) { + localWrite('$scripting.registerContentScripts', `${reason}`); + console.info(reason); + } } + registerInjectables.barrier = false; + return true; } diff --git a/platform/mv3/extension/js/scripting/css-declarative.js b/platform/mv3/extension/js/scripting/css-declarative.js index d5c55552f7869..a0364ce2027fd 100644 --- a/platform/mv3/extension/js/scripting/css-declarative.js +++ b/platform/mv3/extension/js/scripting/css-declarative.js @@ -19,12 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - -/******************************************************************************/ - // Important! // Isolate from global scope (function uBOL_cssDeclarative() { @@ -33,73 +27,41 @@ const declarativeImports = self.declarativeImports || []; self.declarativeImports = undefined; -delete self.declarativeImports; /******************************************************************************/ -const hnParts = []; -try { hnParts.push(...document.location.hostname.split('.')); } -catch(ex) { } -const hnpartslen = hnParts.length; -if ( hnpartslen === 0 ) { return; } - const selectors = []; - -for ( const { argsList, exceptionsMap, hostnamesMap, entitiesMap } of declarativeImports ) { - const todoIndices = new Set(); - const tonotdoIndices = []; - // Exceptions - if ( exceptionsMap.size !== 0 ) { - for ( let i = 0; i < hnpartslen; i++ ) { - const hn = hnParts.slice(i).join('.'); - const excepted = exceptionsMap.get(hn); - if ( excepted ) { tonotdoIndices.push(...excepted); } - } - exceptionsMap.clear(); +const exceptions = []; + +const lookupHostname = (hostname, details, out) => { + let seqi = details.hostnamesMap.get(hostname); + if ( seqi === undefined ) { return; } + const { argsList, argsSeqs } = details; + for (;;) { + const argi = argsSeqs[seqi++]; + const done = argi > 0; + out.push(...argsList[done ? argi : -argi].split('\n')); + if ( done ) { break; } } - // Hostname-based - if ( hostnamesMap.size !== 0 ) { - const collectArgIndices = hn => { - let argsIndices = hostnamesMap.get(hn); - if ( argsIndices === undefined ) { return; } - if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; } - for ( const argsIndex of argsIndices ) { - if ( tonotdoIndices.includes(argsIndex) ) { continue; } - todoIndices.add(argsIndex); - } - }; - for ( let i = 0; i < hnpartslen; i++ ) { - const hn = hnParts.slice(i).join('.'); - collectArgIndices(hn); - } - collectArgIndices('*'); - hostnamesMap.clear(); - } - // Entity-based - if ( entitiesMap.size !== 0 ) { - const n = hnpartslen - 1; - for ( let i = 0; i < n; i++ ) { - for ( let j = n; j > i; j-- ) { - const en = hnParts.slice(i,j).join('.'); - let argsIndices = entitiesMap.get(en); - if ( argsIndices === undefined ) { continue; } - if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; } - for ( const argsIndex of argsIndices ) { - if ( tonotdoIndices.includes(argsIndex) ) { continue; } - todoIndices.add(argsIndex); - } - } - } - entitiesMap.clear(); - } - for ( const i of todoIndices ) { - selectors.push(...argsList[i].map(json => JSON.parse(json))); +}; + +const lookupAll = hostname => { + for ( const details of declarativeImports ) { + lookupHostname(hostname, details, selectors); + lookupHostname(`~${hostname}`, details, exceptions); } - argsList.length = 0; -} +}; + +self.isolatedAPI.forEachHostname(lookupAll, { + hasEntities: declarativeImports.some(a => a.hasEntities) +}); + declarativeImports.length = 0; -if ( selectors.length === 0 ) { return; } +const exceptedSelectors = exceptions.length !== 0 + ? selectors.filter(a => exceptions.includes(a) === false) + : selectors; +if ( exceptedSelectors.length === 0 ) { return; } /******************************************************************************/ @@ -132,26 +94,23 @@ const cssRuleFromProcedural = details => { }; const sheetText = []; -for ( const selector of selectors ) { - const ruleText = cssRuleFromProcedural(selector); +for ( const selector of exceptedSelectors ) { + const details = JSON.parse(selector); + const ruleText = cssRuleFromProcedural(details); if ( ruleText === undefined ) { continue; } sheetText.push(ruleText); } if ( sheetText.length === 0 ) { return; } -(function uBOL_injectCSS(css, count = 10) { - chrome.runtime.sendMessage({ what: 'insertCSS', css }).catch(( ) => { - count -= 1; - if ( count === 0 ) { return; } - uBOL_injectCSS(css, count - 1); - }); -})(sheetText.join('\n')); +chrome.runtime.sendMessage({ + what: 'insertCSS', + css: sheetText.join('\n'), +}).catch(( ) => { +}); /******************************************************************************/ })(); -/******************************************************************************/ - void 0; diff --git a/platform/mv3/extension/js/scripting/css-generic.js b/platform/mv3/extension/js/scripting/css-generic.js index b00ea03bd4c89..f9979a9fbe150 100644 --- a/platform/mv3/extension/js/scripting/css-generic.js +++ b/platform/mv3/extension/js/scripting/css-generic.js @@ -26,10 +26,15 @@ (function uBOL_cssGeneric() { const genericSelectorMap = self.genericSelectorMap || new Map(); -delete self.genericSelectorMap; - +self.genericSelectorMap = undefined; if ( genericSelectorMap.size === 0 ) { return; } +const genericExceptionSieve = self.genericExceptionSieve || new Set(); +self.genericExceptionSieve = undefined; + +const genericExceptionMap = self.genericExceptionMap || new Map(); +self.genericExceptionMap = undefined; + /******************************************************************************/ const maxSurveyTimeSlice = 4; @@ -76,7 +81,11 @@ const uBOL_idFromNode = (node, out) => { const selectorList = genericSelectorMap.get(hash); if ( selectorList === undefined ) { return; } genericSelectorMap.delete(hash); - out.push(selectorList); + if ( genericExceptionSieve.has(hash) ) { + applyExceptions(selectorList, out); + } else { + out.push(selectorList); + } }; // https://github.com/uBlockOrigin/uBlock-issues/discussions/2076 @@ -96,10 +105,28 @@ const uBOL_classesFromNode = (node, out) => { const selectorList = genericSelectorMap.get(hash); if ( selectorList === undefined ) { continue; } genericSelectorMap.delete(hash); - out.push(selectorList); + if ( genericExceptionSieve.has(hash) ) { + applyExceptions(selectorList, out); + } else { + out.push(selectorList); + } } }; +const applyExceptions = (selectorList, out) => { + const selectors = new Set(selectorList.split(',\n')); + self.isolatedAPI.forEachHostname(hostname => { + const exceptions = genericExceptionMap.get(hostname); + if ( exceptions === undefined ) { return; } + for ( const exception of exceptions.split('\n') ) { + selectors.delete(exception); + } + if ( selectors.size === 0 ) { return true; } + }, { hasEntities: true }); + if ( selectors.size === 0 ) { return; } + out.push(Array.from(selectors).join(',\n')); +} + /******************************************************************************/ const pendingNodes = { @@ -187,16 +214,30 @@ const uBOL_processChanges = mutations => { /******************************************************************************/ -const uBOL_injectCSS = (css, count = 10) => { - chrome.runtime.sendMessage({ what: 'insertCSS', css }).catch(( ) => { - count -= 1; - if ( count === 0 ) { return; } - uBOL_injectCSS(css, count - 1); +const uBOL_injectCSS = css => { + chrome.runtime.sendMessage({ + what: 'insertCSS', + css, + }).catch(( ) => { }); }; /******************************************************************************/ +const stopAll = reason => { + if ( domChangeTimer !== undefined ) { + self.clearTimeout(domChangeTimer); + domChangeTimer = undefined; + } + domMutationObserver.disconnect(); + domMutationObserver.takeRecords(); + domMutationObserver = undefined; + genericSelectorMap.clear(); + console.info(`uBOL: Generic cosmetic filtering stopped because ${reason}`); +}; + +/******************************************************************************/ + pendingNodes.add(document); uBOL_processNodes(); @@ -219,20 +260,6 @@ needDomChangeObserver(); /******************************************************************************/ -const stopAll = reason => { - if ( domChangeTimer !== undefined ) { - self.clearTimeout(domChangeTimer); - domChangeTimer = undefined; - } - domMutationObserver.disconnect(); - domMutationObserver.takeRecords(); - domMutationObserver = undefined; - genericSelectorMap.clear(); - console.info(`uBOL: Generic cosmetic filtering stopped because ${reason}`); -}; - -/******************************************************************************/ - })(); /******************************************************************************/ diff --git a/platform/mv3/extension/js/scripting/css-procedural-api.js b/platform/mv3/extension/js/scripting/css-procedural-api.js new file mode 100644 index 0000000000000..4b516271feaa0 --- /dev/null +++ b/platform/mv3/extension/js/scripting/css-procedural-api.js @@ -0,0 +1,763 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2014-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +// Important! +// Isolate from global scope +(function uBOL_cssProceduralAPI() { + +if ( self.cssProceduralAPI !== undefined ) { + if ( self.cssProceduralAPI instanceof Promise === false ) { return; } +} + +/******************************************************************************/ + +const uBOL_injectCSS = css => { + chrome.runtime.sendMessage({ + what: 'insertCSS', + css, + }).catch(( ) => { + }); +}; + +const nonVisualElements = { + head: true, + link: true, + meta: true, + script: true, + style: true, +}; + +const regexFromString = (s, exact = false) => { + if ( s === '' ) { return /^/; } + const match = /^\/(.+)\/([imu]*)$/.exec(s); + if ( match !== null ) { + return new RegExp(match[1], match[2] || undefined); + } + const reStr = s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + return new RegExp(exact ? `^${reStr}$` : reStr); +}; + +/******************************************************************************/ + +// 'P' stands for 'Procedural' + +class PSelectorTask { + begin() { + } + end() { + } +} + +/******************************************************************************/ + +class PSelectorVoidTask extends PSelectorTask { + constructor(task) { + super(); + console.info(`uBO: :${task[0]}() operator does not exist`); + } + transpose() { + } +} + +/******************************************************************************/ + +class PSelectorHasTextTask extends PSelectorTask { + constructor(task) { + super(); + this.needle = regexFromString(task[1]); + } + transpose(node, output) { + if ( this.needle.test(node.textContent) ) { + output.push(node); + } + } +} + +/******************************************************************************/ + +class PSelectorIfTask extends PSelectorTask { + constructor(task) { + super(); + this.pselector = new PSelector(task[1]); + } + transpose(node, output) { + if ( this.pselector.test(node) === this.target ) { + output.push(node); + } + } +} +PSelectorIfTask.prototype.target = true; + +class PSelectorIfNotTask extends PSelectorIfTask { +} +PSelectorIfNotTask.prototype.target = false; + +/******************************************************************************/ + +class PSelectorMatchesAttrTask extends PSelectorTask { + constructor(task) { + super(); + this.reAttr = regexFromString(task[1].attr, true); + this.reValue = regexFromString(task[1].value, true); + } + transpose(node, output) { + const attrs = node.getAttributeNames(); + for ( const attr of attrs ) { + if ( this.reAttr.test(attr) === false ) { continue; } + if ( this.reValue.test(node.getAttribute(attr)) === false ) { continue; } + output.push(node); + } + } +} + +/******************************************************************************/ + +class PSelectorMatchesCSSTask extends PSelectorTask { + constructor(task) { + super(); + this.name = task[1].name; + this.pseudo = task[1].pseudo ? `::${task[1].pseudo}` : null; + let arg0 = task[1].value, arg1; + if ( Array.isArray(arg0) ) { + arg1 = arg0[1]; arg0 = arg0[0]; + } + this.value = new RegExp(arg0, arg1); + } + transpose(node, output) { + const style = window.getComputedStyle(node, this.pseudo); + if ( style !== null && this.value.test(style[this.name]) ) { + output.push(node); + } + } +} +class PSelectorMatchesCSSAfterTask extends PSelectorMatchesCSSTask { + constructor(task) { + super(task); + this.pseudo = '::after'; + } +} + +class PSelectorMatchesCSSBeforeTask extends PSelectorMatchesCSSTask { + constructor(task) { + super(task); + this.pseudo = '::before'; + } +} + +/******************************************************************************/ + +class PSelectorMatchesMediaTask extends PSelectorTask { + constructor(task) { + super(); + this.mql = window.matchMedia(task[1]); + if ( this.mql.media === 'not all' ) { return; } + this.mql.addEventListener('change', ( ) => { + const { proceduralFilterer } = self.cssProceduralAPI; + if ( proceduralFilterer instanceof Object === false ) { return; } + proceduralFilterer.uBOL_DOMChanged(); + }); + } + transpose(node, output) { + if ( this.mql.matches === false ) { return; } + output.push(node); + } +} + +/******************************************************************************/ + +class PSelectorMatchesPathTask extends PSelectorTask { + constructor(task) { + super(); + this.needle = regexFromString( + task[1].replace(/\P{ASCII}/gu, s => encodeURIComponent(s)) + ); + } + transpose(node, output) { + if ( this.needle.test(self.location.pathname + self.location.search) ) { + output.push(node); + } + } +} + +/******************************************************************************/ + +class PSelectorMatchesPropTask extends PSelectorTask { + constructor(task) { + super(); + this.props = task[1].attr.split('.'); + this.reValue = task[1].value !== '' + ? regexFromString(task[1].value, true) + : null; + } + transpose(node, output) { + let value = node; + for ( const prop of this.props ) { + if ( value === undefined ) { return; } + if ( value === null ) { return; } + value = value[prop]; + } + if ( this.reValue === null ) { + if ( value === undefined ) { return; } + } else if ( this.reValue.test(value) === false ) { + return; + } + output.push(node); + } +} + +/******************************************************************************/ + +class PSelectorMinTextLengthTask extends PSelectorTask { + constructor(task) { + super(); + this.min = task[1]; + } + transpose(node, output) { + if ( node.textContent.length >= this.min ) { + output.push(node); + } + } +} + +/******************************************************************************/ + +class PSelectorOthersTask extends PSelectorTask { + constructor() { + super(); + this.targets = new Set(); + } + begin() { + this.targets.clear(); + } + end(output) { + const toKeep = new Set(this.targets); + const toDiscard = new Set(); + const body = document.body; + const head = document.head; + let discard = null; + for ( let keep of this.targets ) { + while ( keep !== null && keep !== body && keep !== head ) { + toKeep.add(keep); + toDiscard.delete(keep); + discard = keep.previousElementSibling; + while ( discard !== null ) { + if ( nonVisualElements[discard.localName] !== true ) { + if ( toKeep.has(discard) === false ) { + toDiscard.add(discard); + } + } + discard = discard.previousElementSibling; + } + discard = keep.nextElementSibling; + while ( discard !== null ) { + if ( nonVisualElements[discard.localName] !== true ) { + if ( toKeep.has(discard) === false ) { + toDiscard.add(discard); + } + } + discard = discard.nextElementSibling; + } + keep = keep.parentElement; + } + } + for ( discard of toDiscard ) { + output.push(discard); + } + this.targets.clear(); + } + transpose(candidate) { + for ( const target of this.targets ) { + if ( target.contains(candidate) ) { return; } + if ( candidate.contains(target) ) { + this.targets.delete(target); + } + } + this.targets.add(candidate); + } +} + +/******************************************************************************/ + +class PSelectorShadowTask extends PSelectorTask { + constructor(task) { + super(); + this.selector = task[1]; + } + transpose(node, output) { + const root = this.openOrClosedShadowRoot(node); + if ( root === null ) { return; } + const nodes = root.querySelectorAll(this.selector); + output.push(...nodes); + } + get openOrClosedShadowRoot() { + if ( PSelectorShadowTask.openOrClosedShadowRoot !== undefined ) { + return PSelectorShadowTask.openOrClosedShadowRoot; + } + if ( typeof chrome === 'object' && chrome !== null ) { + if ( chrome.dom instanceof Object ) { + if ( typeof chrome.dom.openOrClosedShadowRoot === 'function' ) { + PSelectorShadowTask.openOrClosedShadowRoot = + chrome.dom.openOrClosedShadowRoot; + return PSelectorShadowTask.openOrClosedShadowRoot; + } + } + } + PSelectorShadowTask.openOrClosedShadowRoot = node => + node.openOrClosedShadowRoot || null; + return PSelectorShadowTask.openOrClosedShadowRoot; + } +} + +/******************************************************************************/ + +// https://github.com/AdguardTeam/ExtendedCss/issues/31#issuecomment-302391277 +// Prepend `:scope ` if needed. +class PSelectorSpathTask extends PSelectorTask { + constructor(task) { + super(); + this.spath = task[1]; + this.nth = /^(?:\s*[+~]|:)/.test(this.spath); + if ( this.nth ) { return; } + if ( /^\s*>/.test(this.spath) ) { + this.spath = `:scope ${this.spath.trim()}`; + } + } + transpose(node, output) { + const nodes = this.nth + ? PSelectorSpathTask.qsa(node, this.spath) + : node.querySelectorAll(this.spath); + for ( const node of nodes ) { + output.push(node); + } + } + // Helper method for other operators. + static qsa(node, selector) { + const parent = node.parentElement; + if ( parent === null ) { return []; } + let pos = 1; + for (;;) { + node = node.previousElementSibling; + if ( node === null ) { break; } + pos += 1; + } + return parent.querySelectorAll( + `:scope > :nth-child(${pos})${selector}` + ); + } +} + +/******************************************************************************/ + +class PSelectorUpwardTask extends PSelectorTask { + constructor(task) { + super(); + const arg = task[1]; + if ( typeof arg === 'number' ) { + this.i = arg; + } else { + this.s = arg; + } + } + transpose(node, output) { + if ( this.s !== '' ) { + const parent = node.parentElement; + if ( parent === null ) { return; } + node = parent.closest(this.s); + if ( node === null ) { return; } + } else { + let nth = this.i; + for (;;) { + node = node.parentElement; + if ( node === null ) { return; } + nth -= 1; + if ( nth === 0 ) { break; } + } + } + output.push(node); + } +} +PSelectorUpwardTask.prototype.i = 0; +PSelectorUpwardTask.prototype.s = ''; + +/******************************************************************************/ + +class PSelectorWatchAttrs extends PSelectorTask { + constructor(task) { + super(); + this.observer = null; + this.observed = new WeakSet(); + this.observerOptions = { + attributes: true, + subtree: true, + }; + const attrs = task[1]; + if ( Array.isArray(attrs) && attrs.length !== 0 ) { + this.observerOptions.attributeFilter = task[1]; + } + } + // TODO: Is it worth trying to re-apply only the current selector? + handler() { + const { proceduralFilterer } = self.cssProceduralAPI; + if ( proceduralFilterer instanceof Object === false ) { return; } + proceduralFilterer.uBOL_DOMChanged(); + } + transpose(node, output) { + output.push(node); + if ( this.observed.has(node) ) { return; } + if ( this.observer === null ) { + this.observer = new MutationObserver(this.handler); + } + this.observer.observe(node, this.observerOptions); + this.observed.add(node); + } +} + +/******************************************************************************/ + +class PSelectorXpathTask extends PSelectorTask { + constructor(task) { + super(); + this.xpe = document.createExpression(task[1], null); + this.xpr = null; + } + transpose(node, output) { + this.xpr = this.xpe.evaluate( + node, + XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, + this.xpr + ); + let j = this.xpr.snapshotLength; + while ( j-- ) { + const node = this.xpr.snapshotItem(j); + if ( node.nodeType === 1 ) { + output.push(node); + } + } + } +} + +/******************************************************************************/ + +class PSelector { + constructor(o) { + this.selector = o.selector; + this.tasks = []; + const tasks = []; + if ( Array.isArray(o.tasks) === false ) { return; } + for ( const task of o.tasks ) { + const ctor = this.operatorToTaskMap.get(task[0]) || PSelectorVoidTask; + tasks.push(new ctor(task)); + } + this.tasks = tasks; + } + prime(input) { + const root = input || document; + if ( this.selector === '' ) { return [ root ]; } + if ( input !== document ) { + const c0 = this.selector.charCodeAt(0); + if ( c0 === 0x2B /* + */ || c0 === 0x7E /* ~ */ ) { + return Array.from(PSelectorSpathTask.qsa(input, this.selector)); + } else if ( c0 === 0x3E /* > */ ) { + return Array.from(input.querySelectorAll(`:scope ${this.selector}`)); + } + } + return Array.from(root.querySelectorAll(this.selector)); + } + exec(input) { + let nodes = this.prime(input); + for ( const task of this.tasks ) { + if ( nodes.length === 0 ) { break; } + const transposed = []; + task.begin(); + for ( const node of nodes ) { + task.transpose(node, transposed); + } + task.end(transposed); + nodes = transposed; + } + return nodes; + } + test(input) { + const nodes = this.prime(input); + for ( const node of nodes ) { + let output = [ node ]; + for ( const task of this.tasks ) { + const transposed = []; + task.begin(); + for ( const node of output ) { + task.transpose(node, transposed); + } + task.end(transposed); + output = transposed; + if ( output.length === 0 ) { break; } + } + if ( output.length !== 0 ) { return true; } + } + return false; + } +} +PSelector.prototype.operatorToTaskMap = new Map([ + [ 'has', PSelectorIfTask ], + [ 'has-text', PSelectorHasTextTask ], + [ 'if', PSelectorIfTask ], + [ 'if-not', PSelectorIfNotTask ], + [ 'matches-attr', PSelectorMatchesAttrTask ], + [ 'matches-css', PSelectorMatchesCSSTask ], + [ 'matches-css-after', PSelectorMatchesCSSAfterTask ], + [ 'matches-css-before', PSelectorMatchesCSSBeforeTask ], + [ 'matches-media', PSelectorMatchesMediaTask ], + [ 'matches-path', PSelectorMatchesPathTask ], + [ 'matches-prop', PSelectorMatchesPropTask ], + [ 'min-text-length', PSelectorMinTextLengthTask ], + [ 'not', PSelectorIfNotTask ], + [ 'others', PSelectorOthersTask ], + [ 'shadow', PSelectorShadowTask ], + [ 'spath', PSelectorSpathTask ], + [ 'upward', PSelectorUpwardTask ], + [ 'watch-attr', PSelectorWatchAttrs ], + [ 'xpath', PSelectorXpathTask ], +]); + +/******************************************************************************/ + +class PSelectorRoot extends PSelector { + constructor(o) { + super(o); + this.budget = 200; // I arbitrary picked a 1/5 second + this.raw = o.raw; + this.cost = 0; + this.lastAllowanceTime = 0; + this.action = o.action; + } + prime(input) { + try { + return super.prime(input); + } catch { + } + return []; + } + exec(input) { + try { + return super.exec(input); + } catch { + } + return []; + } +} + +/******************************************************************************/ + +class ProceduralFilterer { + constructor() { + this.selectors = []; + this.masterToken = this.randomToken(); + this.styleTokenMap = new Map(); + this.styledNodes = new Set(); + this.timer = undefined; + this.hideStyle = 'display:none!important;'; + } + + addSelectors(selectors) { + for ( const json of selectors ) { + const selector = JSON.parse(json); + const pselector = new PSelectorRoot(selector); + this.primeProceduralSelector(pselector); + this.selectors.push(pselector); + } + } + + // This allows to perform potentially expensive initialization steps + // before the filters are ready to be applied. + primeProceduralSelector(pselector) { + if ( pselector.action === undefined ) { + this.styleTokenFromStyle(this.hideStyle); + } else if ( pselector.action[0] === 'style' ) { + this.styleTokenFromStyle(pselector.action[1]); + } + return pselector; + } + + uBOL_commit() { + if ( this.timer !== undefined ) { + self.cancelAnimationFrame(this.timer); + this.timer = undefined; + } + + // https://github.com/uBlockOrigin/uBlock-issues/issues/341 + // Be ready to unhide nodes which no longer matches any of + // the procedural selectors. + const toUnstyle = this.styledNodes; + this.styledNodes = new Set(); + + let t0 = Date.now(); + + for ( const pselector of this.selectors.values() ) { + const allowance = Math.floor((t0 - pselector.lastAllowanceTime) / 2000); + if ( allowance >= 1 ) { + pselector.budget += allowance * 50; + if ( pselector.budget > 200 ) { pselector.budget = 200; } + pselector.lastAllowanceTime = t0; + } + if ( pselector.budget <= 0 ) { continue; } + const nodes = pselector.exec(); + const t1 = Date.now(); + pselector.budget += t0 - t1; + if ( pselector.budget < -500 ) { + console.info('uBOL: disabling %s', pselector.raw); + pselector.budget = -0x7FFFFFFF; + } + t0 = t1; + if ( nodes.length === 0 ) { continue; } + this.processNodes(nodes, pselector.action); + } + + this.unprocessNodes(toUnstyle); + } + + styleTokenFromStyle(style) { + if ( style === undefined ) { return; } + let styleToken = this.styleTokenMap.get(style); + if ( styleToken !== undefined ) { return styleToken; } + styleToken = this.randomToken(); + this.styleTokenMap.set(style, styleToken); + uBOL_injectCSS(`[${this.masterToken}][${styleToken}]\n{${style}}\n`); + return styleToken; + } + + processNodes(nodes, action) { + const op = action && action[0] || ''; + const arg = op !== '' ? action[1] : ''; + switch ( op ) { + case '': + /* fall through */ + case 'style': { + const styleToken = this.styleTokenFromStyle( + arg === '' ? this.hideStyle : arg + ); + for ( const node of nodes ) { + node.setAttribute(this.masterToken, ''); + node.setAttribute(styleToken, ''); + this.styledNodes.add(node); + } + break; + } + case 'remove': { + for ( const node of nodes ) { + node.remove(); + node.textContent = ''; + } + break; + } + case 'remove-attr': { + const reAttr = regexFromString(arg, true); + for ( const node of nodes ) { + for ( const name of node.getAttributeNames() ) { + if ( reAttr.test(name) === false ) { continue; } + node.removeAttribute(name); + } + } + break; + } + case 'remove-class': { + const reClass = regexFromString(arg, true); + for ( const node of nodes ) { + const cl = node.classList; + for ( const name of cl.values() ) { + if ( reClass.test(name) === false ) { continue; } + cl.remove(name); + } + } + break; + } + default: + break; + } + } + + // TODO: Current assumption is one style per hit element. Could be an + // issue if an element has multiple styling and one styling is + // brought back. Possibly too rare to care about this for now. + unprocessNodes(nodes) { + for ( const node of nodes ) { + if ( this.styledNodes.has(node) ) { continue; } + node.removeAttribute(this.masterToken); + } + } + + randomToken() { + const n = Math.random(); + return String.fromCharCode(n * 25 + 97) + + Math.floor( + (0.25 + n * 0.75) * Number.MAX_SAFE_INTEGER + ).toString(36).slice(-8); + } + + uBOL_DOMChanged() { + if ( this.timer !== undefined ) { return; } + this.timer = self.requestAnimationFrame(( ) => { + this.timer = undefined; + this.uBOL_commit(); + }); + } +} + +/******************************************************************************/ + +self.cssProceduralAPI = { + proceduralFilterer: null, + domObserver: null, + addSelectors(selectors) { + if ( this.proceduralFilterer === null ) { + this.proceduralFilterer = new ProceduralFilterer(); + } + if ( this.domObserver === null ) { + this.domObserver = new MutationObserver(mutations => { + this.onDOMChanged(mutations); + }); + this.domObserver.observe(document, { + childList: true, + subtree: true, + }); + } + this.proceduralFilterer.addSelectors(selectors); + this.proceduralFilterer.uBOL_commit(); + }, + onDOMChanged(mutations) { + for ( const mutation of mutations ) { + for ( const added of mutation.addedNodes ) { + if ( added.nodeType !== 1 ) { continue; } + return this.proceduralFilterer.uBOL_DOMChanged(); + } + for ( const removed of mutation.removedNodes ) { + if ( removed.nodeType !== 1 ) { continue; } + return this.proceduralFilterer.uBOL_DOMChanged(); + } + } + }, +}; + +/******************************************************************************/ + +})(); + +/******************************************************************************/ + +void 0; diff --git a/platform/mv3/extension/js/scripting/css-procedural.js b/platform/mv3/extension/js/scripting/css-procedural.js index 7f50f80989d32..f3d0060899557 100644 --- a/platform/mv3/extension/js/scripting/css-procedural.js +++ b/platform/mv3/extension/js/scripting/css-procedural.js @@ -19,778 +19,62 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - -/******************************************************************************/ - // Important! // Isolate from global scope -(function uBOL_cssProcedural() { +(async function uBOL_cssProcedural() { /******************************************************************************/ const proceduralImports = self.proceduralImports || []; self.proceduralImports = undefined; -delete self.proceduralImports; /******************************************************************************/ -const hnParts = []; -try { hnParts.push(...document.location.hostname.split('.')); } -catch(ex) { } -const hnpartslen = hnParts.length; -if ( hnpartslen === 0 ) { return; } - const selectors = []; - -for ( const { argsList, exceptionsMap, hostnamesMap, entitiesMap } of proceduralImports ) { - const todoIndices = new Set(); - const tonotdoIndices = []; - // Exceptions - if ( exceptionsMap.size !== 0 ) { - for ( let i = 0; i < hnpartslen; i++ ) { - const hn = hnParts.slice(i).join('.'); - const excepted = exceptionsMap.get(hn); - if ( excepted ) { tonotdoIndices.push(...excepted); } - } - exceptionsMap.clear(); +const exceptions = []; + +const lookupHostname = (hostname, details, out) => { + let seqi = details.hostnamesMap.get(hostname); + if ( seqi === undefined ) { return; } + const { argsList, argsSeqs } = details; + for (;;) { + const argi = argsSeqs[seqi++]; + const done = argi > 0; + out.push(...argsList[done ? argi : -argi]); + if ( done ) { break; } } - // Hostname-based - if ( hostnamesMap.size !== 0 ) { - const collectArgIndices = hn => { - let argsIndices = hostnamesMap.get(hn); - if ( argsIndices === undefined ) { return; } - if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; } - for ( const argsIndex of argsIndices ) { - if ( tonotdoIndices.includes(argsIndex) ) { continue; } - todoIndices.add(argsIndex); - } - }; - for ( let i = 0; i < hnpartslen; i++ ) { - const hn = hnParts.slice(i).join('.'); - collectArgIndices(hn); - } - collectArgIndices('*'); - hostnamesMap.clear(); - } - // Entity-based - if ( entitiesMap.size !== 0 ) { - const n = hnpartslen - 1; - for ( let i = 0; i < n; i++ ) { - for ( let j = n; j > i; j-- ) { - const en = hnParts.slice(i,j).join('.'); - let argsIndices = entitiesMap.get(en); - if ( argsIndices === undefined ) { continue; } - if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; } - for ( const argsIndex of argsIndices ) { - if ( tonotdoIndices.includes(argsIndex) ) { continue; } - todoIndices.add(argsIndex); - } - } - } - entitiesMap.clear(); - } - for ( const i of todoIndices ) { - selectors.push(...argsList[i].map(json => JSON.parse(json))); - } - argsList.length = 0; -} -proceduralImports.length = 0; - -if ( selectors.length === 0 ) { return; } - -/******************************************************************************/ - -const uBOL_injectCSS = (css, count = 10) => { - chrome.runtime.sendMessage({ what: 'insertCSS', css }).catch(( ) => { - count -= 1; - if ( count === 0 ) { return; } - uBOL_injectCSS(css, count - 1); - }); }; -const nonVisualElements = { - script: true, - style: true, -}; - -const regexFromString = (s, exact = false) => { - if ( s === '' ) { return /^/; } - const match = /^\/(.+)\/([i]?)$/.exec(s); - if ( match !== null ) { - return new RegExp(match[1], match[2] || undefined); +const lookupAll = hostname => { + for ( const details of proceduralImports ) { + lookupHostname(hostname, details, selectors); + lookupHostname(`~${hostname}`, details, exceptions); } - const reStr = s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - return new RegExp(exact ? `^${reStr}$` : reStr, 'i'); }; -/******************************************************************************/ - -// 'P' stands for 'Procedural' - -class PSelectorTask { - begin() { - } - end() { - } -} - -/******************************************************************************/ - -class PSelectorVoidTask extends PSelectorTask { - constructor(task) { - super(); - console.info(`uBO: :${task[0]}() operator does not exist`); - } - transpose() { - } -} - -/******************************************************************************/ - -class PSelectorHasTextTask extends PSelectorTask { - constructor(task) { - super(); - this.needle = regexFromString(task[1]); - } - transpose(node, output) { - if ( this.needle.test(node.textContent) ) { - output.push(node); - } - } -} - -/******************************************************************************/ - -class PSelectorIfTask extends PSelectorTask { - constructor(task) { - super(); - this.pselector = new PSelector(task[1]); - } - transpose(node, output) { - if ( this.pselector.test(node) === this.target ) { - output.push(node); - } - } -} -PSelectorIfTask.prototype.target = true; - -class PSelectorIfNotTask extends PSelectorIfTask { -} -PSelectorIfNotTask.prototype.target = false; - -/******************************************************************************/ - -class PSelectorMatchesAttrTask extends PSelectorTask { - constructor(task) { - super(); - this.reAttr = regexFromString(task[1].attr, true); - this.reValue = regexFromString(task[1].value, true); - } - transpose(node, output) { - const attrs = node.getAttributeNames(); - for ( const attr of attrs ) { - if ( this.reAttr.test(attr) === false ) { continue; } - if ( this.reValue.test(node.getAttribute(attr)) === false ) { continue; } - output.push(node); - } - } -} - -/******************************************************************************/ - -class PSelectorMatchesCSSTask extends PSelectorTask { - constructor(task) { - super(); - this.name = task[1].name; - this.pseudo = task[1].pseudo ? `::${task[1].pseudo}` : null; - let arg0 = task[1].value, arg1; - if ( Array.isArray(arg0) ) { - arg1 = arg0[1]; arg0 = arg0[0]; - } - this.value = new RegExp(arg0, arg1); - } - transpose(node, output) { - const style = window.getComputedStyle(node, this.pseudo); - if ( style !== null && this.value.test(style[this.name]) ) { - output.push(node); - } - } -} -class PSelectorMatchesCSSAfterTask extends PSelectorMatchesCSSTask { - constructor(task) { - super(task); - this.pseudo = '::after'; - } -} - -class PSelectorMatchesCSSBeforeTask extends PSelectorMatchesCSSTask { - constructor(task) { - super(task); - this.pseudo = '::before'; - } -} - -/******************************************************************************/ - -class PSelectorMatchesMediaTask extends PSelectorTask { - constructor(task) { - super(); - this.mql = window.matchMedia(task[1]); - if ( this.mql.media === 'not all' ) { return; } - this.mql.addEventListener('change', ( ) => { - if ( proceduralFilterer instanceof Object === false ) { return; } - proceduralFilterer.onDOMChanged([ null ]); - }); - } - transpose(node, output) { - if ( this.mql.matches === false ) { return; } - output.push(node); - } -} - -/******************************************************************************/ - -class PSelectorMatchesPathTask extends PSelectorTask { - constructor(task) { - super(); - this.needle = regexFromString( - task[1].replace(/\P{ASCII}/gu, s => encodeURIComponent(s)) - ); - } - transpose(node, output) { - if ( this.needle.test(self.location.pathname + self.location.search) ) { - output.push(node); - } - } -} - -/******************************************************************************/ - -class PSelectorMinTextLengthTask extends PSelectorTask { - constructor(task) { - super(); - this.min = task[1]; - } - transpose(node, output) { - if ( node.textContent.length >= this.min ) { - output.push(node); - } - } -} - -/******************************************************************************/ - -class PSelectorOthersTask extends PSelectorTask { - constructor() { - super(); - this.targets = new Set(); - } - begin() { - this.targets.clear(); - } - end(output) { - const toKeep = new Set(this.targets); - const toDiscard = new Set(); - const body = document.body; - let discard = null; - for ( let keep of this.targets ) { - while ( keep !== null && keep !== body ) { - toKeep.add(keep); - toDiscard.delete(keep); - discard = keep.previousElementSibling; - while ( discard !== null ) { - if ( - nonVisualElements[discard.localName] !== true && - 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); - } - discard = discard.nextElementSibling; - } - keep = keep.parentElement; - } - } - for ( discard of toDiscard ) { - output.push(discard); - } - this.targets.clear(); - } - transpose(candidate) { - for ( const target of this.targets ) { - if ( target.contains(candidate) ) { return; } - if ( candidate.contains(target) ) { - this.targets.delete(target); - } - } - this.targets.add(candidate); - } -} - -/******************************************************************************/ - -class PSelectorShadowTask extends PSelectorTask { - constructor(task) { - super(); - this.selector = task[1]; - } - transpose(node, output) { - const root = this.openOrClosedShadowRoot(node); - if ( root === null ) { return; } - const nodes = root.querySelectorAll(this.selector); - output.push(...nodes); - } - get openOrClosedShadowRoot() { - if ( PSelectorShadowTask.openOrClosedShadowRoot !== undefined ) { - return PSelectorShadowTask.openOrClosedShadowRoot; - } - if ( typeof chrome === 'object' && chrome !== null ) { - if ( chrome.dom instanceof Object ) { - if ( typeof chrome.dom.openOrClosedShadowRoot === 'function' ) { - PSelectorShadowTask.openOrClosedShadowRoot = - chrome.dom.openOrClosedShadowRoot; - return PSelectorShadowTask.openOrClosedShadowRoot; - } - } - } - PSelectorShadowTask.openOrClosedShadowRoot = node => - node.openOrClosedShadowRoot || null; - return PSelectorShadowTask.openOrClosedShadowRoot; - } -} - -/******************************************************************************/ - -// https://github.com/AdguardTeam/ExtendedCss/issues/31#issuecomment-302391277 -// Prepend `:scope ` if needed. -class PSelectorSpathTask extends PSelectorTask { - constructor(task) { - super(); - this.spath = task[1]; - this.nth = /^(?:\s*[+~]|:)/.test(this.spath); - if ( this.nth ) { return; } - if ( /^\s*>/.test(this.spath) ) { - this.spath = `:scope ${this.spath.trim()}`; - } - } - transpose(node, output) { - const nodes = this.nth - ? PSelectorSpathTask.qsa(node, this.spath) - : node.querySelectorAll(this.spath); - for ( const node of nodes ) { - output.push(node); - } - } - // Helper method for other operators. - static qsa(node, selector) { - const parent = node.parentElement; - if ( parent === null ) { return []; } - let pos = 1; - for (;;) { - node = node.previousElementSibling; - if ( node === null ) { break; } - pos += 1; - } - return parent.querySelectorAll( - `:scope > :nth-child(${pos})${selector}` - ); - } -} - -/******************************************************************************/ - -class PSelectorUpwardTask extends PSelectorTask { - constructor(task) { - super(); - const arg = task[1]; - if ( typeof arg === 'number' ) { - this.i = arg; - } else { - this.s = arg; - } - } - transpose(node, output) { - if ( this.s !== '' ) { - const parent = node.parentElement; - if ( parent === null ) { return; } - node = parent.closest(this.s); - if ( node === null ) { return; } - } else { - let nth = this.i; - for (;;) { - node = node.parentElement; - if ( node === null ) { return; } - nth -= 1; - if ( nth === 0 ) { break; } - } - } - output.push(node); - } -} -PSelectorUpwardTask.prototype.i = 0; -PSelectorUpwardTask.prototype.s = ''; - -/******************************************************************************/ - -class PSelectorWatchAttrs extends PSelectorTask { - constructor(task) { - super(); - this.observer = null; - this.observed = new WeakSet(); - this.observerOptions = { - attributes: true, - subtree: true, - }; - const attrs = task[1]; - if ( Array.isArray(attrs) && attrs.length !== 0 ) { - this.observerOptions.attributeFilter = task[1]; - } - } - // TODO: Is it worth trying to re-apply only the current selector? - handler() { - if ( proceduralFilterer instanceof Object ) { - proceduralFilterer.onDOMChanged([ null ]); - } - } - transpose(node, output) { - output.push(node); - if ( this.observed.has(node) ) { return; } - if ( this.observer === null ) { - this.observer = new MutationObserver(this.handler); - } - this.observer.observe(node, this.observerOptions); - this.observed.add(node); - } -} - -/******************************************************************************/ - -class PSelectorXpathTask extends PSelectorTask { - constructor(task) { - super(); - this.xpe = document.createExpression(task[1], null); - this.xpr = null; - } - transpose(node, output) { - this.xpr = this.xpe.evaluate( - node, - XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, - this.xpr - ); - let j = this.xpr.snapshotLength; - while ( j-- ) { - const node = this.xpr.snapshotItem(j); - if ( node.nodeType === 1 ) { - output.push(node); - } - } - } -} - -/******************************************************************************/ +self.isolatedAPI.forEachHostname(lookupAll, { + hasEntities: proceduralImports.some(a => a.hasEntities) +}); -class PSelector { - constructor(o) { - this.selector = o.selector; - this.tasks = []; - const tasks = []; - if ( Array.isArray(o.tasks) === false ) { return; } - for ( const task of o.tasks ) { - const ctor = this.operatorToTaskMap.get(task[0]) || PSelectorVoidTask; - tasks.push(new ctor(task)); - } - this.tasks = tasks; - } - prime(input) { - const root = input || document; - if ( this.selector === '' ) { return [ root ]; } - if ( input !== document ) { - const c0 = this.selector.charCodeAt(0); - if ( c0 === 0x2B /* + */ || c0 === 0x7E /* ~ */ ) { - return Array.from(PSelectorSpathTask.qsa(input, this.selector)); - } else if ( c0 === 0x3E /* > */ ) { - return Array.from(input.querySelectorAll(`:scope ${this.selector}`)); - } - } - return Array.from(root.querySelectorAll(this.selector)); - } - exec(input) { - let nodes = this.prime(input); - for ( const task of this.tasks ) { - if ( nodes.length === 0 ) { break; } - const transposed = []; - task.begin(); - for ( const node of nodes ) { - task.transpose(node, transposed); - } - task.end(transposed); - nodes = transposed; - } - return nodes; - } - test(input) { - const nodes = this.prime(input); - for ( const node of nodes ) { - let output = [ node ]; - for ( const task of this.tasks ) { - const transposed = []; - task.begin(); - for ( const node of output ) { - task.transpose(node, transposed); - } - task.end(transposed); - output = transposed; - if ( output.length === 0 ) { break; } - } - if ( output.length !== 0 ) { return true; } - } - return false; - } -} -PSelector.prototype.operatorToTaskMap = new Map([ - [ 'has', PSelectorIfTask ], - [ 'has-text', PSelectorHasTextTask ], - [ 'if', PSelectorIfTask ], - [ 'if-not', PSelectorIfNotTask ], - [ 'matches-attr', PSelectorMatchesAttrTask ], - [ 'matches-css', PSelectorMatchesCSSTask ], - [ 'matches-css-after', PSelectorMatchesCSSAfterTask ], - [ 'matches-css-before', PSelectorMatchesCSSBeforeTask ], - [ 'matches-media', PSelectorMatchesMediaTask ], - [ 'matches-path', PSelectorMatchesPathTask ], - [ 'min-text-length', PSelectorMinTextLengthTask ], - [ 'not', PSelectorIfNotTask ], - [ 'others', PSelectorOthersTask ], - [ 'shadow', PSelectorShadowTask ], - [ 'spath', PSelectorSpathTask ], - [ 'upward', PSelectorUpwardTask ], - [ 'watch-attr', PSelectorWatchAttrs ], - [ 'xpath', PSelectorXpathTask ], -]); +proceduralImports.length = 0; -/******************************************************************************/ +const exceptedSelectors = exceptions.length !== 0 + ? selectors.filter(a => exceptions.includes(a) === false) + : selectors; +if ( exceptedSelectors.length === 0 ) { return; } -class PSelectorRoot extends PSelector { - constructor(o) { - super(o); - this.budget = 200; // I arbitrary picked a 1/5 second - this.raw = o.raw; - this.cost = 0; - this.lastAllowanceTime = 0; - this.action = o.action; - } - prime(input) { - try { - return super.prime(input); - } catch (ex) { - } - return []; - } - exec(input) { - try { - return super.exec(input); - } catch (ex) { - } - return []; - } +if ( self.cssProceduralAPI === undefined ) { + self.cssProceduralAPI = chrome.runtime.sendMessage({ + what: 'injectCSSProceduralAPI' + }).catch(( ) => { + }); } - -/******************************************************************************/ - -class ProceduralFilterer { - constructor(selectors) { - this.selectors = []; - this.masterToken = this.randomToken(); - this.styleTokenMap = new Map(); - this.styledNodes = new Set(); - this.timer = undefined; - this.hideStyle = 'display:none!important;'; - this.addSelectors(selectors); - // Important: commit now (do not go through onDOMChanged) to be sure - // first pass is going to happen asap. - this.uBOL_commitNow(); - } - - addSelectors() { - for ( const selector of selectors ) { - const pselector = new PSelectorRoot(selector); - this.primeProceduralSelector(pselector); - this.selectors.push(pselector); - } - this.onDOMChanged(); - } - - // This allows to perform potentially expensive initialization steps - // before the filters are ready to be applied. - primeProceduralSelector(pselector) { - if ( pselector.action === undefined ) { - this.styleTokenFromStyle(this.hideStyle); - } else if ( pselector.action[0] === 'style' ) { - this.styleTokenFromStyle(pselector.action[1]); - } - return pselector; - } - - uBOL_commitNow() { - // https://github.com/uBlockOrigin/uBlock-issues/issues/341 - // Be ready to unhide nodes which no longer matches any of - // the procedural selectors. - const toUnstyle = this.styledNodes; - this.styledNodes = new Set(); - - let t0 = Date.now(); - - for ( const pselector of this.selectors.values() ) { - const allowance = Math.floor((t0 - pselector.lastAllowanceTime) / 2000); - if ( allowance >= 1 ) { - pselector.budget += allowance * 50; - if ( pselector.budget > 200 ) { pselector.budget = 200; } - pselector.lastAllowanceTime = t0; - } - if ( pselector.budget <= 0 ) { continue; } - const nodes = pselector.exec(); - const t1 = Date.now(); - pselector.budget += t0 - t1; - if ( pselector.budget < -500 ) { - console.info('uBOL: disabling %s', pselector.raw); - pselector.budget = -0x7FFFFFFF; - } - t0 = t1; - if ( nodes.length === 0 ) { continue; } - this.processNodes(nodes, pselector.action); - } - - this.unprocessNodes(toUnstyle); - } - - styleTokenFromStyle(style) { - if ( style === undefined ) { return; } - let styleToken = this.styleTokenMap.get(style); - if ( styleToken !== undefined ) { return styleToken; } - styleToken = this.randomToken(); - this.styleTokenMap.set(style, styleToken); - uBOL_injectCSS(`[${this.masterToken}][${styleToken}]\n{${style}}\n`); - return styleToken; - } - - processNodes(nodes, action) { - const op = action && action[0] || ''; - const arg = op !== '' ? action[1] : ''; - switch ( op ) { - case '': - /* fall through */ - case 'style': { - const styleToken = this.styleTokenFromStyle( - arg === '' ? this.hideStyle : arg - ); - for ( const node of nodes ) { - node.setAttribute(this.masterToken, ''); - node.setAttribute(styleToken, ''); - this.styledNodes.add(node); - } - break; - } - case 'remove': { - for ( const node of nodes ) { - node.remove(); - node.textContent = ''; - } - break; - } - case 'remove-attr': { - const reAttr = regexFromString(arg, true); - for ( const node of nodes ) { - for ( const name of node.getAttributeNames() ) { - if ( reAttr.test(name) === false ) { continue; } - node.removeAttribute(name); - } - } - break; - } - case 'remove-class': { - const reClass = regexFromString(arg, true); - for ( const node of nodes ) { - const cl = node.classList; - for ( const name of cl.values() ) { - if ( reClass.test(name) === false ) { continue; } - cl.remove(name); - } - } - break; - } - default: - break; - } - } - - // TODO: Current assumption is one style per hit element. Could be an - // issue if an element has multiple styling and one styling is - // brought back. Possibly too rare to care about this for now. - unprocessNodes(nodes) { - for ( const node of nodes ) { - if ( this.styledNodes.has(node) ) { continue; } - node.removeAttribute(this.masterToken); - } - } - - randomToken() { - const n = Math.random(); - return String.fromCharCode(n * 25 + 97) + - Math.floor( - (0.25 + n * 0.75) * Number.MAX_SAFE_INTEGER - ).toString(36).slice(-8); - } - - onDOMChanged() { - if ( this.timer !== undefined ) { return; } - this.timer = self.requestAnimationFrame(( ) => { - this.timer = undefined; - this.uBOL_commitNow(); - }); - } +if ( self.cssProceduralAPI instanceof Promise ) { + await self.cssProceduralAPI; } +if ( self.cssProceduralAPI instanceof Object === false ) { return; } -/******************************************************************************/ - -const proceduralFilterer = new ProceduralFilterer(selectors); - -const observer = new MutationObserver(mutations => { - let domChanged = false; - for ( let i = 0; i < mutations.length && !domChanged; i++ ) { - const mutation = mutations[i]; - for ( const added of mutation.addedNodes ) { - if ( added.nodeType !== 1 ) { continue; } - domChanged = true; - break; - } - if ( domChanged === false ) { - for ( const removed of mutation.removedNodes ) { - if ( removed.nodeType !== 1 ) { continue; } - domChanged = true; - break; - } - } - } - if ( domChanged === false ) { return; } - proceduralFilterer.onDOMChanged(); -}); - -observer.observe(document, { - childList: true, - subtree: true, -}); +self.cssProceduralAPI.addSelectors(exceptedSelectors); /******************************************************************************/ diff --git a/platform/mv3/extension/js/scripting/css-specific.js b/platform/mv3/extension/js/scripting/css-specific.js index faf997cc05f00..2d2c0db37a456 100644 --- a/platform/mv3/extension/js/scripting/css-specific.js +++ b/platform/mv3/extension/js/scripting/css-specific.js @@ -19,12 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - -/******************************************************************************/ - // Important! // Isolate from global scope (function uBOL_cssSpecific() { @@ -33,88 +27,50 @@ const specificImports = self.specificImports || []; self.specificImports = undefined; -delete self.specificImports; /******************************************************************************/ -const hnParts = []; -try { hnParts.push(...document.location.hostname.split('.')); } -catch(ex) { } -const hnpartslen = hnParts.length; -if ( hnpartslen === 0 ) { return; } - const selectors = []; - -for ( const { argsList, exceptionsMap, hostnamesMap, entitiesMap } of specificImports ) { - const todoIndices = new Set(); - const tonotdoIndices = []; - // Exceptions - if ( exceptionsMap.size !== 0 ) { - for ( let i = 0; i < hnpartslen; i++ ) { - const hn = hnParts.slice(i).join('.'); - const excepted = exceptionsMap.get(hn); - if ( excepted ) { tonotdoIndices.push(...excepted); } - } - exceptionsMap.clear(); - } - // Hostname-based - if ( hostnamesMap.size !== 0 ) { - const collectArgIndices = hn => { - let argsIndices = hostnamesMap.get(hn); - if ( argsIndices === undefined ) { return; } - if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; } - for ( const argsIndex of argsIndices ) { - if ( tonotdoIndices.includes(argsIndex) ) { continue; } - todoIndices.add(argsIndex); - } - }; - for ( let i = 0; i < hnpartslen; i++ ) { - const hn = hnParts.slice(i).join('.'); - collectArgIndices(hn); - } - collectArgIndices('*'); - hostnamesMap.clear(); - } - // Entity-based - if ( entitiesMap.size !== 0 ) { - const n = hnpartslen - 1; - for ( let i = 0; i < n; i++ ) { - for ( let j = n; j > i; j-- ) { - const en = hnParts.slice(i,j).join('.'); - let argsIndices = entitiesMap.get(en); - if ( argsIndices === undefined ) { continue; } - if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; } - for ( const argsIndex of argsIndices ) { - if ( tonotdoIndices.includes(argsIndex) ) { continue; } - todoIndices.add(argsIndex); - } - } - } - entitiesMap.clear(); +const exceptions = []; + +const lookupHostname = (hostname, details, out) => { + let seqi = details.hostnamesMap.get(hostname); + if ( seqi === undefined ) { return; } + const { argsList, argsSeqs } = details; + for (;;) { + const argi = argsSeqs[seqi++]; + const done = argi > 0; + out.push(...argsList[done ? argi : -argi].split('\n')); + if ( done ) { break; } } - for ( const i of todoIndices ) { - selectors.push(argsList[i]); +}; + +const lookupAll = hostname => { + for ( const details of specificImports ) { + lookupHostname(hostname, details, selectors); + lookupHostname(`~${hostname}`, details, exceptions); } - argsList.length = 0; -} -specificImports.length = 0; +}; -if ( selectors.length === 0 ) { return; } +self.isolatedAPI.forEachHostname(lookupAll, { + hasEntities: specificImports.some(a => a.hasEntities) +}); -/******************************************************************************/ +specificImports.length = 0; -(function uBOL_injectCSS(css, count = 10) { - chrome.runtime.sendMessage({ what: 'insertCSS', css }).catch(( ) => { - count -= 1; - if ( count === 0 ) { return; } - uBOL_injectCSS(css, count - 1); - }); -})(`${selectors.join(',')}{display:none!important;}`); +const exceptedSelectors = exceptions.length !== 0 + ? selectors.filter(a => exceptions.includes(a) === false) + : selectors; +if ( exceptedSelectors.length === 0 ) { return; } + +chrome.runtime.sendMessage({ + what: 'insertCSS', + css: `${exceptedSelectors.join(',')}{display:none!important;}`, +}).catch(( ) => { +}); /******************************************************************************/ })(); -/******************************************************************************/ - void 0; diff --git a/platform/mv3/extension/js/scripting/css-user.js b/platform/mv3/extension/js/scripting/css-user.js new file mode 100644 index 0000000000000..3adae6628edbb --- /dev/null +++ b/platform/mv3/extension/js/scripting/css-user.js @@ -0,0 +1,37 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2019-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +(async function uBOL_cssUser() { + +/******************************************************************************/ + +const docURL = new URL(document.baseURI); +chrome.runtime.sendMessage({ + what: 'injectCustomFilters', + hostname: docURL.hostname, +}).catch(( ) => { +}); + +/******************************************************************************/ + +})(); + +void 0; diff --git a/platform/mv3/extension/js/scripting/isolated-api.js b/platform/mv3/extension/js/scripting/isolated-api.js new file mode 100644 index 0000000000000..4781f935c251f --- /dev/null +++ b/platform/mv3/extension/js/scripting/isolated-api.js @@ -0,0 +1,80 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2022-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock/ + +*/ + +/******************************************************************************/ + +(api => { + if ( typeof api === 'object' ) { return; } + + const isolatedAPI = self.isolatedAPI = {}; + + const hostnameStack = (( ) => { + const docloc = document.location; + const origins = [ docloc.origin ]; + if ( docloc.ancestorOrigins ) { + origins.push(...docloc.ancestorOrigins); + } + return origins.map((origin, i) => { + const beg = origin.lastIndexOf('://'); + if ( beg === -1 ) { return; } + const hn1 = origin.slice(beg+3) + const end = hn1.indexOf(':'); + const hn2 = end === -1 ? hn1 : hn1.slice(0, end); + return { hnparts: hn2.split('.'), i }; + }).filter(a => a !== undefined); + })(); + + const forEachHostname = (entry, callback, details) => { + const hnparts = entry.hnparts; + const hnpartslen = hnparts.length; + if ( hnpartslen === 0 ) { return; } + for ( let i = 0; i < hnpartslen; i++ ) { + const r = callback(`${hnparts.slice(i).join('.')}`, details); + if ( r !== undefined ) { return r; } + } + if ( details?.hasEntities !== true ) { return; } + const n = hnpartslen - 1; + for ( let i = 0; i < n; i++ ) { + for ( let j = n; j > i; j-- ) { + const r = callback(`${hnparts.slice(i,j).join('.')}.*`, details); + if ( r !== undefined ) { return r; } + } + } + }; + + isolatedAPI.forEachHostname = (callback, details) => { + if ( hostnameStack.length === 0 ) { return; } + return forEachHostname(hostnameStack[0], callback, details); + }; + + isolatedAPI.forEachHostnameAncestors = (callback, details) => { + for ( const entry of hostnameStack ) { + if ( entry.i === 0 ) { continue; } + const r = forEachHostname(entry, callback, details); + if ( r !== undefined ) { return r; } + } + }; +})(self.isolatedAPI); + +/******************************************************************************/ + +void 0; \ No newline at end of file diff --git a/platform/mv3/extension/js/scripting/picker.js b/platform/mv3/extension/js/scripting/picker.js new file mode 100644 index 0000000000000..124d4dcb7e8ff --- /dev/null +++ b/platform/mv3/extension/js/scripting/picker.js @@ -0,0 +1,270 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +(async ( ) => { + +/******************************************************************************/ + +const ubolOverlay = self.ubolOverlay; +if ( ubolOverlay === undefined ) { return; } +if ( ubolOverlay.file === '/picker-ui.html' ) { return; } + +/******************************************************************************/ + +function attributeNameFromPart(part) { + const pos = part.search(/\^?=/); + return part.slice(1, pos); +} + +function selectorFromAddresses(partsDB, addresses) { + const selector = []; + let majorLast = -1; + for ( const address of addresses ) { + const major = address >>> 12; + if ( majorLast !== -1 ) { + const delta = majorLast - major; + if ( delta > 1 ) { + selector.push(' '); + } else if ( delta === 1 ) { + selector.push(' > '); + } + } + majorLast = major; + const part = partsDB.get(address); + selector.push( + (address & 0xF) === 3 + ? `[${attributeNameFromPart(part)}]` + : part + ); + } + return selector.join(''); +} + +/******************************************************************************* + * + * Selector part address: + * 0b00000000_00000000_0000 + * | | | + * | | +-- 4-bit: Descriptor + * | +------- 8-bit: Part index + * +---------------- 8-bit: List index + * Descriptor: + * - 0: tag name + * - 1: id + * - 2: class + * - 3: attribute + * - 4: :nth-of-type + * List index: 0 is deepest + * + * Selector part addresses are used to reference parts in associated database. + * + * */ + +function candidatesAtPoint(x, y) { + // We need at least one element. + let elem = null; + if ( typeof x === 'number' ) { + elem = ubolOverlay.elementFromPoint(x, y); + } else if ( x instanceof HTMLElement ) { + elem = x; + x = undefined; + } + + const partsDB = new Map(); + const listParts = []; + while ( elem && elem !== document.body ) { + const tagName = elem.localName; + const addressMajor = listParts.length << 12; + partsDB.set(addressMajor, CSS.escape(tagName)); + const parts = [ addressMajor ]; + // Id + if ( typeof elem.id === 'string' && elem.id !== '' ) { + const address = addressMajor | parts.length << 4 | 1; + partsDB.set(address, `#${CSS.escape(elem.id)}`); + parts.push(address); + } + // Classes + for ( const name of elem.classList.values() ) { + const address = addressMajor | parts.length << 4 | 2; + partsDB.set(address, `.${CSS.escape(name)}`); + parts.push(address); + } + // Attributes + for ( const name of elem.getAttributeNames() ) { + if ( name === 'id' || name === 'class' ) { continue; } + if ( excludedAttributeExpansion.includes(name) ) { + const address = addressMajor | parts.length << 4 | 3; + partsDB.set(address, `[${CSS.escape(name)}]`); + parts.push(address); + continue; + } + let value = elem.getAttribute(name); + const pos = value.search(/[\n\r]/); + if ( pos !== -1 ) { + value = value.slice(0, pos); + } + const address = addressMajor | parts.length << 4 | 3; + partsDB.set(address, `[${CSS.escape(name)}="${value}"]`); + parts.push(address); + } + // https://github.com/chrisaljoudi/uBlock/issues/637 + // If the selector is still ambiguous at this point, further narrow + // using `:nth-of-type`. + const parentNode = elem.parentNode; + if ( ubolOverlay.qsa(parentNode, `:scope > ${selectorFromAddresses(partsDB, parts)}`).length > 1 ) { + let i = 1; + while ( elem.previousSibling !== null ) { + elem = elem.previousSibling; + if ( typeof elem.localName !== 'string' ) { continue; } + if ( elem.localName !== tagName ) { continue; } + i++; + } + const address = addressMajor | parts.length << 4 | 4; + partsDB.set(address, `:nth-of-type(${i})`); + parts.push(address); + } + listParts.push(parts); + elem = elem.parentElement; + } + if ( listParts.length === 0 ) { return; } + + const sliderCandidates = []; + for ( let i = 0, n = listParts.length; i < n; i++ ) { + sliderCandidates.push(listParts[i]); + for ( let j = i + 1; j < n; j++ ) { + sliderCandidates.push([ + ...listParts[j], + ...sliderCandidates.at(-1), + ]); + } + } + const sliderMap = new Map(); + for ( const candidates of sliderCandidates ) { + if ( candidates.some(a => (a & 0xF) === 1) ) { + const selectorPath = candidates.filter(a => (a & 0xF) === 1); + sliderMap.set(JSON.stringify(selectorPath), 0); + } else if ( candidates.some(a => (a & 0xF) === 4) ) { + const selectorPath = candidates.filter(a => { + return a &= 0xF, a === 0 || a === 4; + }); + sliderMap.set(JSON.stringify(selectorPath), 0); + } + if ( candidates.some(a => (a & 0xF) === 2) ) { + const selectorPath = candidates.filter(a => { + return a &= 0xF, a === 0 || a === 2; + }); + sliderMap.set(JSON.stringify(selectorPath), 0); + } + const selectorPath = candidates.filter(a => { + return a &= 0xF, a === 0 || a === 3; + }); + sliderMap.set(JSON.stringify(selectorPath), 0); + } + sliderMap.delete('[]'); + const elemToIdMap = new Map(); + const resultSetMap = new Map(); + let elemId = 1; + for ( const json of sliderMap.keys() ) { + const addresses = JSON.parse(json); + const selector = selectorFromAddresses(partsDB, addresses); + if ( excludedSelectors.includes(selector) ) { continue; } + const elems = ubolOverlay.qsa(document, selector); + if ( elems.length === 0 ) { continue; } + const resultSet = []; + for ( const elem of elems ) { + if ( elemToIdMap.has(elem) === false ) { + elemToIdMap.set(elem, elemId++); + } + resultSet.push(elemToIdMap.get(elem)); + } + const resultSetKey = JSON.stringify(resultSet.sort()); + const current = resultSetMap.get(resultSetKey); + if ( current ) { + if ( current.length < addresses.length ) { continue; } + if ( current.length === addresses.length ) { + if ( addresses.some(a => (a & 0xF) === 2) === false ) { + if ( current.some(a => (a & 0xF) === 2) ) { continue; } + } + } + } + resultSetMap.set(resultSetKey, addresses); + } + const sliderParts = Array.from(resultSetMap).toSorted((a, b) => { + let amajor = a[1].at(-1) >>> 12; + let bmajor = b[1].at(-1) >>> 12; + if ( amajor !== bmajor ) { return bmajor - amajor; } + amajor = a[1].at(0) >>> 12; + bmajor = b[1].at(0) >>> 12; + if ( amajor !== bmajor ) { return bmajor - amajor; } + if ( a[0].length !== b[0].length ) { + return b[0].length - a[0].length; + } + return b[1].length - a[1].length; + }).map(a => a[1]); + return { + partsDB: Array.from(partsDB), + listParts, + sliderParts, + }; +} + +const excludedAttributeExpansion = [ + 'sizes', + 'srcset', +]; +const excludedSelectors = [ + 'div', + 'span', +]; + +/******************************************************************************/ + +function onMessage(msg) { + switch ( msg.what ) { + case 'injectCustomFilters': + return ubolOverlay.sendMessage({ what: 'injectCustomFilters', + hostname: ubolOverlay.url.hostname, + }); + case 'uninjectCustomFilters': + return ubolOverlay.sendMessage({ what: 'uninjectCustomFilters', + hostname: ubolOverlay.url.hostname, + }); + case 'candidatesAtPoint': + return candidatesAtPoint(msg.mx, msg.my, msg.broad); + case 'insertCSS': + return ubolOverlay.sendMessage(msg); + case 'removeCSS': + return ubolOverlay.sendMessage(msg); + default: + break; + } +} + +/******************************************************************************/ + +await ubolOverlay.install('/picker-ui.html', onMessage); + +/******************************************************************************/ + +})(); + + +void 0; diff --git a/platform/mv3/extension/js/scripting/tool-overlay.js b/platform/mv3/extension/js/scripting/tool-overlay.js new file mode 100644 index 0000000000000..e2708b15999a0 --- /dev/null +++ b/platform/mv3/extension/js/scripting/tool-overlay.js @@ -0,0 +1,360 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +(function uBOLOverlay() { + +/******************************************************************************/ + +if ( self.ubolOverlay ) { + self.ubolOverlay.stop(); + self.ubolOverlay = undefined; +} + +self.ubolOverlay = { + file: '', + webext: typeof browser === 'object' ? browser : chrome, + url: new URL(document.baseURI), + port: null, + highlightedElements: [], + secretAttr: (( ) => { + let secret = String.fromCharCode((Math.random() * 26) + 97); + do { + secret += (Math.floor(Math.random() * 2147483647) + 2147483647) + .toString(36) + .slice(2); + } while ( secret.length < 8 ); + return secret; + })(), + + start() { + const cssStyle = [ + 'background: transparent', + 'border: 0', + 'border-radius: 0', + 'box-shadow: none', + 'color-scheme: light dark', + 'display: block', + 'filter: none', + 'height: 100vh', + ' height: 100svh', + 'left: 0', + 'margin: 0', + 'max-height: none', + 'max-width: none', + 'min-height: unset', + 'min-width: unset', + 'opacity: 1', + 'outline: 0', + 'padding: 0', + 'pointer-events: auto', + 'position: fixed', + 'top: 0', + 'transform: none', + 'visibility: hidden', + 'width: 100%', + 'z-index: 2147483647', + '' + ].join(' !important;\n'); + this.pickerCSS = [ + `:root > [${this.secretAttr}] { ${cssStyle} }`, + `:root > [${this.secretAttr}-loaded] { visibility: visible !important; }`, + `:root > [${this.secretAttr}-click] { pointer-events: none !important; }`, + ].join('\n'); + this.sendMessage({ what: 'insertCSS', css: this.pickerCSS }); + self.addEventListener('scroll', this.onViewportChanged, { passive: true }); + self.addEventListener('resize', this.onViewportChanged, { passive: true }); + self.addEventListener('keydown', this.onKeyPressed, true); + }, + + stop() { + if ( this.pickerCSS ) { + this.sendMessage({ what: 'removeCSS', css: this.pickerCSS }); + this.pickerCSS = undefined; + } + self.removeEventListener('scroll', this.onViewportChanged, { passive: true }); + self.removeEventListener('resize', this.onViewportChanged, { passive: true }); + self.removeEventListener('keydown', this.onKeyPressed, true); + if ( this.frame ) { + this.frame.remove(); + this.frame = null; + } + if ( this.port ) { + this.port.close(); + this.port.onmessage = null; + this.port.onmessageerror = null; + this.port = null; + } + this.onmessage = null; + self.ubolOverlay = undefined; + }, + + onViewportChanged() { + self.ubolOverlay.highlightUpdate(); + }, + + onKeyPressed(ev) { + if ( ev.key !== 'Escape' && ev.which !== 27 ) { return; } + ev.stopPropagation(); + ev.preventDefault(); + if ( self.ubolOverlay.onmessage ) { + self.ubolOverlay.onmessage({ what: 'quitTool' }); + } + }, + + sendMessage(msg) { + try { + return this.webext.runtime.sendMessage(msg).catch(( ) => { }); + } catch { + } + }, + + onMessage(wrapped) { + // Response to script-initiated message? + if ( typeof wrapped?.fromScriptId === 'number' ) { + const resolve = this.pendingMessages.get(wrapped.fromScriptId); + if ( resolve ) { + this.pendingMessages.delete(wrapped.fromScriptId); + resolve(wrapped.msg); + } + return; + } + const onmessage = this.onmessage; + const msg = wrapped.msg || wrapped; + let response; + switch ( msg.what ) { + case 'startTool': + this.start(); + break; + case 'quitTool': + this.stop(); + break; + case 'highlightElementAtPoint': + this.highlightElementAtPoint(msg.mx, msg.my); + break; + case 'highlightFromSelector': { + const { elems, error } = this.elementsFromSelector(msg.selector); + this.highlightElements(elems); + if ( msg.scrollTo && elems.length !== 0 ) { + elems[0].scrollIntoView({ block: 'nearest', inline: 'nearest' }); + } + response = { count: elems.length, error }; + break; + } + case 'unhighlight': + this.unhighlight(); + break; + } + response = onmessage && onmessage(msg) || response; + // Send response if this is frame-initiated message + if ( wrapped?.fromFrameId && this.port ) { + const { fromFrameId } = wrapped; + if ( response instanceof Promise ) { + response.then(response => { + if ( this.port === null ) { return; } + this.port.postMessage({ fromFrameId, msg: response }); + }); + } else { + this.port.postMessage({ fromFrameId, msg: response }); + } + } + }, + postMessage(msg) { + if ( this.port === null ) { return; } + const wrapped = { + fromScriptId: this.messageId++, + msg, + }; + return new Promise(resolve => { + this.pendingMessages.set(wrapped.fromScriptId, resolve); + this.port.postMessage(wrapped); + }); + }, + messageId: 1, + pendingMessages: new Map(), + + getElementBoundingClientRect(elem) { + let rect = typeof elem.getBoundingClientRect === 'function' + ? elem.getBoundingClientRect() + : { height: 0, left: 0, top: 0, width: 0 }; + + // https://github.com/gorhill/uBlock/issues/1024 + // Try not returning an empty bounding rect. + if ( rect.width !== 0 && rect.height !== 0 ) { + return rect; + } + if ( elem.shadowRoot instanceof DocumentFragment ) { + return this.getElementBoundingClientRect(elem.shadowRoot); + } + let left = rect.left, + right = left + rect.width, + top = rect.top, + bottom = top + rect.height; + for ( const child of elem.children ) { + rect = this.getElementBoundingClientRect(child); + if ( rect.width === 0 || rect.height === 0 ) { continue; } + if ( rect.left < left ) { left = rect.left; } + if ( rect.right > right ) { right = rect.right; } + if ( rect.top < top ) { top = rect.top; } + if ( rect.bottom > bottom ) { bottom = rect.bottom; } + } + return { + left, right, + top, bottom, + width: right - left, + height: bottom - top, + }; + }, + + highlightUpdate() { + const ow = self.innerWidth; + const oh = self.innerHeight; + const islands = []; + for ( const elem of this.highlightedElements ) { + const rect = this.getElementBoundingClientRect(elem); + // Ignore offscreen areas + if ( rect.left > ow ) { continue; } + if ( rect.top > oh ) { continue; } + if ( rect.left + rect.width < 0 ) { continue; } + if ( rect.top + rect.height < 0 ) { continue; } + islands.push( + `M${rect.left} ${rect.top}h${rect.width}v${rect.height}h-${rect.width}z` + ); + } + this.port.postMessage({ + what: 'svgPaths', + ocean: `M0 0h${ow}v${oh}h-${ow}z`, + islands: islands.join(''), + }); + }, + + highlightElements(iter = []) { + this.highlightedElements = + Array.from(iter).filter(a => + a instanceof Element && a !== this.frame + ); + this.highlightUpdate(); + }, + + qsa(node, selector) { + if ( node !== null ) { + try { + const elems = node.querySelectorAll(selector); + this.qsa.error = undefined; + return elems; + } catch (reason) { + this.qsa.error = `${reason}`; + } + } + return []; + }, + + elementFromPoint(x, y) { + if ( x !== undefined ) { + this.lastX = x; this.lastY = y; + } else if ( this.lastX !== undefined ) { + x = this.lastX; y = this.lastY; + } else { + return null; + } + const magicAttr = `${this.secretAttr}-click`; + this.frame.setAttribute(magicAttr, ''); + let elem = document.elementFromPoint(x, y); + if ( elem === document.body || elem === document.documentElement ) { + elem = null; + } + // https://github.com/uBlockOrigin/uBlock-issues/issues/380 + this.frame.removeAttribute(magicAttr); + return elem; + }, + + elementsFromSelector(selector) { + const elems = this.qsa(document, selector); + return { elems, error: this.qsa.error }; + }, + + highlightElementAtPoint(x, y) { + const elem = self.ubolOverlay.elementFromPoint(x, y); + this.highlightElements([ elem ]); + }, + + unhighlight() { + this.highlightElements([]); + }, + + async install(file, onmessage) { + this.file = file; + const dynamicURL = new URL(this.webext.runtime.getURL(file)); + return new Promise(resolve => { + const frame = document.createElement('iframe'); + const secretAttr = this.secretAttr; + frame.setAttribute(secretAttr, ''); + const onLoad = ( ) => { + frame.onload = null; + frame.setAttribute(`${secretAttr}-loaded`, ''); + const channel = new MessageChannel(); + const port = channel.port1; + port.onmessage = ev => { + self.ubolOverlay && + self.ubolOverlay.onMessage(ev.data || {}) + }; + port.onmessageerror = ( ) => { + self.ubolOverlay && + self.ubolOverlay.onMessage({ what: 'quitTool' }) + }; + const realURL = new URL(dynamicURL); + realURL.hostname = + self.ubolOverlay.webext.i18n.getMessage('@@extension_id'); + frame.contentWindow.postMessage( + { + what: 'startOverlay', + url: document.baseURI, + width: self.innerWidth, + height: self.innerHeight, + }, + realURL.origin, + [ channel.port2 ] + ); + frame.contentWindow.focus(); + self.ubolOverlay.onmessage = onmessage; + self.ubolOverlay.port = port; + self.ubolOverlay.frame = frame; + resolve(true); + }; + if ( dynamicURL.protocol !== 'safari-web-extension:' ) { + frame.onload = ( ) => { + frame.onload = onLoad; + frame.contentWindow.location = dynamicURL.href; + }; + } else { + frame.onload = onLoad; + frame.setAttribute('src', dynamicURL.href); + } + document.documentElement.append(frame); + }); + }, +}; + +/******************************************************************************/ + +})(); + + +void 0; diff --git a/platform/mv3/extension/js/scripting/toolbar-icon.js b/platform/mv3/extension/js/scripting/toolbar-icon.js new file mode 100644 index 0000000000000..c5843a05c77c2 --- /dev/null +++ b/platform/mv3/extension/js/scripting/toolbar-icon.js @@ -0,0 +1,27 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +(function uBOL_toggleToolbarIcon() { + chrome.runtime.sendMessage({ + what: 'toggleToolbarIcon', + }).catch(( ) => { + }); +})(); diff --git a/platform/mv3/extension/js/scripting/unpicker.js b/platform/mv3/extension/js/scripting/unpicker.js new file mode 100644 index 0000000000000..41c5fb71c514f --- /dev/null +++ b/platform/mv3/extension/js/scripting/unpicker.js @@ -0,0 +1,61 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +(async ( ) => { + +/******************************************************************************/ + +const ubolOverlay = self.ubolOverlay; +if ( ubolOverlay === undefined ) { return; } +if ( ubolOverlay.file === '/unpicker-ui.html' ) { return; } + +/******************************************************************************/ + +function onMessage(msg) { + switch ( msg.what ) { + case 'injectCustomFilters': + return ubolOverlay.sendMessage({ what: 'injectCustomFilters', + hostname: ubolOverlay.url.hostname, + }); + case 'uninjectCustomFilters': + return ubolOverlay.sendMessage({ what: 'uninjectCustomFilters', + hostname: ubolOverlay.url.hostname, + }); + case 'removeCustomFilter': + return ubolOverlay.sendMessage({ what: 'removeCustomFilter', + hostname: ubolOverlay.url.hostname, + selector: msg.selector, + }); + default: + break; + } +} + +/******************************************************************************/ + +await ubolOverlay.install('/unpicker-ui.html', onMessage); + +/******************************************************************************/ + +})(); + + +void 0; diff --git a/platform/mv3/extension/js/scripting/zapper.js b/platform/mv3/extension/js/scripting/zapper.js new file mode 100644 index 0000000000000..9d9628f76ccee --- /dev/null +++ b/platform/mv3/extension/js/scripting/zapper.js @@ -0,0 +1,138 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +(async ( ) => { + +/******************************************************************************/ + +const ubolOverlay = self.ubolOverlay; +if ( ubolOverlay === undefined ) { return; } +if ( ubolOverlay.file === '/zapper-ui.html' ) { return; } + +/******************************************************************************/ + +// https://www.reddit.com/r/uBlockOrigin/comments/bktxtb/scrolling_doesnt_work/emn901o +// Override 'fixed' position property on body element if present. + +// With touch-driven devices, first highlight the element and remove only +// when tapping again the highlighted area. + +function zapElementAtPoint(mx, my, options) { + if ( options.highlight ) { + const elem = ubolOverlay.elementFromPoint(mx, my); + if ( elem ) { + ubolOverlay.highlightElements([ elem ]); + } + return; + } + + let elemToRemove = ubolOverlay.highlightedElements?.[0] ?? null; + if ( elemToRemove === null && mx !== undefined ) { + elemToRemove = ubolOverlay.elementFromPoint(mx, my); + } + + if ( elemToRemove instanceof Element === false ) { return; } + + const getStyleValue = (elem, prop) => { + const style = window.getComputedStyle(elem); + return style ? style[prop] : ''; + }; + + // Heuristic to detect scroll-locking: remove such lock when detected. + let maybeScrollLocked = elemToRemove.shadowRoot instanceof DocumentFragment; + if ( maybeScrollLocked === false ) { + let elem = elemToRemove; + do { + maybeScrollLocked = + parseInt(getStyleValue(elem, 'zIndex'), 10) >= 1000 || + getStyleValue(elem, 'position') === 'fixed'; + elem = elem.parentElement; + } while ( elem !== null && maybeScrollLocked === false ); + } + if ( maybeScrollLocked ) { + const doc = document; + if ( getStyleValue(doc.body, 'overflowY') === 'hidden' ) { + doc.body.style.setProperty('overflow', 'auto', 'important'); + } + if ( getStyleValue(doc.body, 'position') === 'fixed' ) { + doc.body.style.setProperty('position', 'initial', 'important'); + } + if ( getStyleValue(doc.documentElement, 'position') === 'fixed' ) { + doc.documentElement.style.setProperty('position', 'initial', 'important'); + } + if ( getStyleValue(doc.documentElement, 'overflowY') === 'hidden' ) { + doc.documentElement.style.setProperty('overflow', 'auto', 'important'); + } + } + elemToRemove.remove(); + ubolOverlay.highlightElementAtPoint(mx, my); +} + +/******************************************************************************/ + +function onKeyPressed(ev) { + if ( ev.key !== 'Delete' && ev.key !== 'Backspace' ) { return; } + ev.stopPropagation(); + ev.preventDefault(); + zapElementAtPoint(); +} + +/******************************************************************************/ + +function startZapper() { + self.addEventListener('keydown', onKeyPressed, true); +} + +function quitZapper() { + self.removeEventListener('keydown', onKeyPressed, true); +} + +/******************************************************************************/ + +function onMessage(msg) { + switch ( msg.what ) { + case 'startTool': + startZapper(); + break; + case 'quitTool': + quitZapper(); + break; + case 'zapElementAtPoint': + zapElementAtPoint(msg.mx, msg.my, msg.options); + if ( msg.options.highlight !== true && msg.options.stay !== true ) { + quitZapper(); + } + break; + default: + break; + } +} + +/******************************************************************************/ + +await ubolOverlay.install('/zapper-ui.html', onMessage); + +/******************************************************************************/ + +})(); + + +void 0; diff --git a/platform/mv3/extension/js/settings.js b/platform/mv3/extension/js/settings.js index 6f50055df6554..254e321d7c7da 100644 --- a/platform/mv3/extension/js/settings.js +++ b/platform/mv3/extension/js/settings.js @@ -19,183 +19,23 @@ 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 punycode from './punycode.js'; +import { browser, sendMessage } from './ext.js'; +import { dom, qs$ } from './dom.js'; +import { hashFromIterable } from './dashboard.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'; } } @@ -207,7 +47,6 @@ function renderWidgets() { } renderDefaultMode(); - renderTrustedSites(); qs$('#autoReload input[type="checkbox"]').checked = cachedRulesetData.autoReload; @@ -221,26 +60,19 @@ 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.hasOmnipotence; + input.checked = canStrictBlock && cachedRulesetData.strictBlockMode; + dom.attr(input, 'disabled', canStrictBlock ? null : ''); + } + + { + const state = Boolean(cachedRulesetData.developerMode) && + cachedRulesetData.disabledFeatures?.includes('develop') !== true; + dom.body.dataset.develop = `${state}`; + dom.prop('#developerMode input[type="checkbox"]', 'checked', state); } - dom.text('#listsOfBlockedHostsPrompt', i18n$('perRulesetStats') - .replace('{{ruleCount}}', ruleCount.toLocaleString()) - .replace('{{filterCount}}', filterCount.toLocaleString()) - ); - - dom.cl.toggle(dom.body, 'noMoreRuleset', - rulesetCount === cachedRulesetData.maxNumberOfEnabledRulesets - ); } /******************************************************************************/ @@ -261,17 +93,18 @@ async function onFilteringModeChange(ev) { const newLevel = parseInt(input.value, 10); switch ( newLevel ) { - case 1: { // Revoke broad permissions - await browser.permissions.remove({ - origins: [ '' ] + case 1: { + const actualLevel = await sendMessage({ + what: 'setDefaultFilteringMode', + level: newLevel, }); - cachedRulesetData.defaultFilteringMode = 1; + cachedRulesetData.defaultFilteringMode = actualLevel; break; } case 2: - case 3: { // Request broad permissions + case 3: { const granted = await browser.permissions.request({ - origins: [ '' ] + origins: [ '' ], }); if ( granted ) { const actualLevel = await sendMessage({ @@ -279,13 +112,14 @@ async function onFilteringModeChange(ev) { level: newLevel, }); cachedRulesetData.defaultFilteringMode = actualLevel; + cachedRulesetData.hasOmnipotence = true; } break; } default: break; } - renderFilterLists(); + renderFilterLists(cachedRulesetData); renderWidgets(); } @@ -312,146 +146,35 @@ dom.on('#showBlockedCount input[type="checkbox"]', 'change', ev => { }); }); -/******************************************************************************/ - -function renderTrustedSites() { - const textarea = qs$('#trustedSites'); - const hostnames = cachedRulesetData.trustedSites; - textarea.value = hostnames.map(hn => punycode.toUnicode(hn)).join('\n'); - if ( textarea.value !== '' ) { - textarea.value += '\n'; - } -} - -function changeTrustedSites() { - const hostnames = getStagedTrustedSites(); - const hash = hashFromIterable(cachedRulesetData.trustedSites); - if ( hashFromIterable(hostnames) === hash ) { return; } +dom.on('#strictBlockMode input[type="checkbox"]', 'change', ev => { sendMessage({ - what: 'setTrustedSites', - hostnames, - }); -} - -function getStagedTrustedSites() { - const textarea = qs$('#trustedSites'); - return textarea.value.split(/\s/).map(hn => { - try { - return punycode.toASCII( - (new URL(`https://${hn}/`)).hostname - ); - } catch(_) { - } - return ''; - }).filter(hn => hn !== ''); -} - -dom.on('#trustedSites', 'blur', changeTrustedSites); - -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, + what: 'setStrictBlockMode', + state: ev.target.checked, }); - - 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 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); +dom.on('#developerMode input[type="checkbox"]', 'change', ev => { + const state = ev.target.checked; + sendMessage({ what: 'setDeveloperMode', state }); + dom.body.dataset.develop = `${state}`; }); /******************************************************************************/ -const bc = new self.BroadcastChannel('uBOL'); +function listen() { + const bc = new self.BroadcastChannel('uBOL'); + bc.onmessage = listen.onmessage; +} -bc.onmessage = ev => { +listen.onmessage = ev => { const message = ev.data; if ( message instanceof Object === false ) { return; } const local = cachedRulesetData; let render = false; - // Keep added sites which have not yet been committed - if ( message.trustedSites !== undefined ) { - if ( hashFromIterable(message.trustedSites) !== hashFromIterable(local.trustedSites) ) { - const current = new Set(local.trustedSites); - const staged = new Set(getStagedTrustedSites()); - for ( const hn of staged ) { - if ( current.has(hn) === false ) { continue; } - staged.delete(hn); - } - const combined = Array.from(new Set([ ...message.trustedSites, ...staged ])); - local.trustedSites = combined; + if ( message.hasOmnipotence !== undefined ) { + if ( message.hasOmnipotence !== local.hasOmnipotence ) { + local.hasOmnipotence = message.hasOmnipotence; render = true; } } @@ -477,6 +200,27 @@ bc.onmessage = ev => { } } + if ( message.strictBlockMode !== undefined ) { + if ( message.strictBlockMode !== local.strictBlockMode ) { + local.strictBlockMode = message.strictBlockMode; + render = true; + } + } + + if ( message.developerMode !== undefined ) { + if ( message.developerMode !== local.developerMode ) { + local.developerMode = message.developerMode; + render = true; + } + } + + if ( message.adminRulesets !== undefined ) { + if ( hashFromIterable(message.adminRulesets) !== hashFromIterable(local.adminRulesets) ) { + local.adminRulesets = message.adminRulesets; + render = true; + } + } + if ( message.enabledRulesets !== undefined ) { if ( hashFromIterable(message.enabledRulesets) !== hashFromIterable(local.enabledRulesets) ) { local.enabledRulesets = message.enabledRulesets; @@ -485,7 +229,7 @@ bc.onmessage = ev => { } if ( render === false ) { return; } - renderFilterLists(); + renderFilterLists(cachedRulesetData); renderWidgets(); }; @@ -496,13 +240,15 @@ 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(); - } catch(ex) { + dom.cl.remove(dom.body, 'loading'); + } catch(reason) { + console.error(reason); } + 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..23e1372a2cd9f --- /dev/null +++ b/platform/mv3/extension/js/strictblock.js @@ -0,0 +1,295 @@ +/******************************************************************************* + + 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; +} + +/******************************************************************************/ + +const toURL = new URL('about:blank'); +const toFinalURL = new URL('about:blank'); + +try { + toURL.href = self.location.hash.slice(1); + toFinalURL.href = toURL.href; +} catch { +} + +dom.clear('#theURL > p > span:first-of-type'); +qs$('#theURL > p > span:first-of-type').append(urlToFragment(toURL.href)); + +/******************************************************************************/ + +async function proceed() { + const permanent = qs$('#disableWarning').checked; + // Do not exclude current hostname from strict-block ruleset if a urlskip + // directive to another site is in effect. + // TODO: what if the urlskip directive leads to a different subdomain on + // same site? + if ( toFinalURL.hostname !== toURL.hostname && permanent !== true ) { + return window.location.replace(toFinalURL.href); + } + await sendMessage({ + what: 'excludeFromStrictBlock', + hostname: toURL.hostname, + permanent, + }); + window.location.replace(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 { + 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'); + }); +})(); + +/******************************************************************************/ + +// Find which list caused the blocking. +(async ( ) => { + const rulesetDetails = await rulesetDetailsPromise; + let iList = -1; + const searchInList = async i => { + if ( iList !== -1 ) { return; } + const rules = await fetchJSON(`/rulesets/strictblock/${rulesetDetails[i].id}`); + if ( iList !== -1 ) { return; } + const toHref = toURL.href; + for ( const rule of rules ) { + const { regexFilter, requestDomains } = rule.condition; + let matchesDomain = requestDomains === undefined; + if ( requestDomains ) { + let hn = toURL.hostname; + for (;;) { + if ( requestDomains.includes(hn) ) { + matchesDomain = true; + break; + } + const pos = hn.indexOf('.'); + if ( pos === -1 ) { break; } + hn = hn.slice(pos+1); + } + if ( matchesDomain === false ) { continue; } + } + const re = new RegExp(regexFilter); + const matchesRegex = re.test(toHref); + if ( matchesDomain && matchesRegex ) { + iList = i; + } + } + }; + 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); + const toHn = toURL.hostname; + const matchesHn = hn => { + if ( toHn.endsWith(hn) === false ) { return false; } + if ( hn.length === toHn.length ) { return true; } + return toHn.charAt(toHn.length - hn.length - 1) === '.'; + }; + 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; } + if ( urlskip.hostnames ) { + if ( urlskip.hostnames.some(hn => matchesHn(hn)) === false ) { + continue; + } + } + const finalURL = urlSkip(toURL.href, false, urlskip.steps); + if ( finalURL === undefined ) { continue; } + toFinalURL.href = finalURL; + 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/theme.js b/platform/mv3/extension/js/theme.js index a61384e4aa9d2..d816250a3d512 100644 --- a/platform/mv3/extension/js/theme.js +++ b/platform/mv3/extension/js/theme.js @@ -19,17 +19,22 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - import { dom } from './dom.js'; /******************************************************************************/ -const mql = self.matchMedia('(prefers-color-scheme: dark)'); -const theme = mql instanceof Object && mql.matches === true - ? 'dark' - : 'light'; -dom.cl.toggle(dom.html, 'dark', theme === 'dark'); -dom.cl.toggle(dom.html, 'light', theme !== 'dark'); +{ + const mql = self.matchMedia('(prefers-color-scheme: dark)'); + const theme = mql instanceof Object && mql.matches === true + ? 'dark' + : 'light'; + dom.cl.toggle(dom.html, 'dark', theme === 'dark'); + dom.cl.toggle(dom.html, 'light', theme !== 'dark'); +} + +{ + const mql = self.matchMedia('(hover: hover)'); + const isTouchScreen = mql.matches !== true; + dom.cl.toggle(dom.html, 'mobile', isTouchScreen); + dom.cl.toggle(dom.html, 'desktop', isTouchScreen === false); +} diff --git a/platform/mv3/extension/js/tool-overlay-ui.js b/platform/mv3/extension/js/tool-overlay-ui.js new file mode 100644 index 0000000000000..609d548bf6b28 --- /dev/null +++ b/platform/mv3/extension/js/tool-overlay-ui.js @@ -0,0 +1,241 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { dom, qs$ } from './dom.js'; +import { sendMessage } from './ext.js'; + +/******************************************************************************/ + +export const toolOverlay = { + url: new URL('about:blank'), + svgRoot: qs$('svg#overlay'), + svgOcean: qs$('svg#overlay > path'), + svgIslands: qs$('svg#overlay > path + path'), + emptyPath: 'M0 0', + port: null, + + start(onmessage) { + this.onmessage = onmessage; + globalThis.addEventListener('message', ev => { + const msg = ev.data || {}; + if ( msg.what !== 'startOverlay' ) { return; } + if ( Array.isArray(ev.ports) === false ) { return; } + if ( ev.ports.length === 0 ) { return; } + toolOverlay.port = ev.ports[0]; + toolOverlay.port.onmessage = ev => { + this.onMessage(ev.data || {}); + }; + toolOverlay.port.onmessageerror = ( ) => { + this.onmessage({ what: 'stopTool' }); + }; + this.moveable = qs$('aside:has(#move)'); + if ( this.moveable !== null ) { + dom.on('aside #move', 'pointerdown', ev => { + this.mover(ev); + }); + } + this.onMessage({ what: 'startTool', + url: msg.url, + width: msg.width, + height: msg.height, + }); + dom.cl.remove(dom.body, 'loading'); + }, { once: true }); + }, + + stop() { + this.highlightElementUnderMouse(false); + if ( this.port ) { + this.port.postMessage({ what: 'quitTool' }); + this.port.onmessage = null; + this.port.onmessageerror = null; + this.port = null; + } + }, + + onMessage(wrapped) { + // Response to frame-initiated message? + if ( typeof wrapped?.fromFrameId === 'number' ) { + const resolve = this.pendingMessages.get(wrapped.fromFrameId); + if ( resolve ) { + this.pendingMessages.delete(wrapped.fromFrameId); + resolve(wrapped.msg); + } + return; + } + const msg = wrapped.msg || wrapped; + switch ( msg.what ) { + case 'startTool': { + this.url.href = msg.url; + const ow = msg.width; + const oh = msg.height; + this.svgOcean.setAttribute('d', `M0 0h${ow}v${oh}h-${ow}z`); + break; + } + case 'svgPaths': + this.svgOcean.setAttribute('d', msg.ocean + msg.islands); + this.svgIslands.setAttribute('d', msg.islands || this.emptyPath); + break; + default: + break; + } + const response = this.onmessage && this.onmessage(msg) || undefined; + // Send response if this is script-initiated message + if ( wrapped?.fromScriptId && this.port ) { + const { fromScriptId } = wrapped; + if ( response instanceof Promise ) { + response.then(response => { + if ( this.port === null ) { return; } + this.port.postMessage({ fromScriptId, msg: response }); + }); + } else { + this.port.postMessage({ fromScriptId, msg: response }); + } + } + }, + postMessage(msg) { + if ( this.port === null ) { return; } + const wrapped = { + fromFrameId: this.messageId++, + msg, + }; + return new Promise(resolve => { + this.pendingMessages.set(wrapped.fromFrameId, resolve); + this.port.postMessage(wrapped); + }); + }, + messageId: 1, + pendingMessages: new Map(), + + sendMessage(msg) { + return sendMessage(msg); + }, + + highlightElementUnderMouse(state) { + if ( dom.cl.has(dom.root, 'mobile') ) { return; } + if ( state === this.mstrackerOn ) { return; } + this.mstrackerOn = state; + if ( this.mstrackerOn ) { + dom.on(document, 'mousemove', this.onHover, { passive: true }); + return; + } + dom.off(document, 'mousemove', this.onHover, { passive: true }); + if ( this.mstrackerTimer === undefined ) { return; } + self.cancelAnimationFrame(this.mstrackerTimer); + this.mstrackerTimer = undefined; + }, + onTimer() { + toolOverlay.mstrackerTimer = undefined; + if ( toolOverlay.port === null ) { return; } + toolOverlay.port.postMessage({ + what: 'highlightElementAtPoint', + mx: toolOverlay.mstrackerX, + my: toolOverlay.mstrackerY, + }); + }, + onHover(ev) { + toolOverlay.mstrackerX = ev.clientX; + toolOverlay.mstrackerY = ev.clientY; + if ( toolOverlay.mstrackerTimer !== undefined ) { return; } + toolOverlay.mstrackerTimer = + self.requestAnimationFrame(toolOverlay.onTimer); + }, + mstrackerOn: false, + mstrackerX: 0, mstrackerY: 0, + mstrackerTimer: undefined, + + mover(ev) { + const target = ev.target; + if ( target.matches('#move') === false ) { return; } + if ( dom.cl.has(this.moveable, 'moving') ) { return; } + target.setPointerCapture(ev.pointerId); + this.moverIsTouch = ev.type.startsWith('touch'); + if ( this.moverIsTouch ) { + const touch = ev.touches[0]; + this.moverX0 = touch.pageX; + this.moverY0 = touch.pageY; + } else { + this.moverX0 = ev.pageX; + this.moverY0 = ev.pageY; + } + const rect = this.moveable.getBoundingClientRect(); + this.moverCX0 = rect.x + rect.width / 2; + this.moverCY0 = rect.y + rect.height / 2; + dom.cl.add(this.moveable, 'moving'); + self.addEventListener('pointermove', this.moverMoveAsync, { capture: true }); + self.addEventListener('pointerup', this.moverStop, { capture: true, once: true }); + ev.stopPropagation(); + ev.preventDefault(); + }, + moverMove() { + this.moverTimer = undefined; + const cx1 = this.moverCX0 + this.moverX1 - this.moverX0; + const cy1 = this.moverCY0 + this.moverY1 - this.moverY0; + const rootW = dom.root.clientWidth; + const rootH = dom.root.clientHeight; + const moveableW = this.moveable.clientWidth; + const moveableH = this.moveable.clientHeight; + if ( cx1 < rootW / 2 ) { + this.moveable.style.setProperty('left', `${Math.max(cx1-moveableW/2,2)}px`); + this.moveable.style.removeProperty('right'); + } else { + this.moveable.style.removeProperty('left'); + this.moveable.style.setProperty('right', `${Math.max(rootW-cx1-moveableW/2,2)}px`); + } + if ( cy1 < rootH / 2 ) { + this.moveable.style.setProperty('top', `${Math.max(cy1-moveableH/2,2)}px`); + this.moveable.style.removeProperty('bottom'); + } else { + this.moveable.style.removeProperty('top'); + this.moveable.style.setProperty('bottom', `${Math.max(rootH-cy1-moveableH/2,2)}px`); + } + }, + moverMoveAsync(ev) { + if ( toolOverlay.moverTimer !== undefined ) { return; } + if ( toolOverlay.moverIsTouch ) { + const touch = ev.touches[0]; + toolOverlay.moverX1 = touch.pageX; + toolOverlay.moverY1 = touch.pageY; + } else { + toolOverlay.moverX1 = ev.pageX; + toolOverlay.moverY1 = ev.pageY; + } + toolOverlay.moverTimer = self.requestAnimationFrame(( ) => { + toolOverlay.moverMove(); + }); + }, + moverStop(ev) { + if ( dom.cl.has(toolOverlay.moveable, 'moving') === false ) { return; } + dom.cl.remove(toolOverlay.moveable, 'moving'); + self.removeEventListener('pointermove', toolOverlay.moverMoveAsync, { capture: true }); + ev.target.releasePointerCapture(ev.pointerId); + ev.stopPropagation(); + ev.preventDefault(); + }, + moveable: null, + moverIsTouch: false, + moverX0: 0, moverY0: 0, + moverX1: 0, moverY1: 0, + moverCX0: 0, moverCY0: 0, + moverTimer: undefined, +}; + +/******************************************************************************/ diff --git a/platform/mv3/extension/js/troubleshooting.js b/platform/mv3/extension/js/troubleshooting.js new file mode 100644 index 0000000000000..4300d1eb15d42 --- /dev/null +++ b/platform/mv3/extension/js/troubleshooting.js @@ -0,0 +1,123 @@ +/******************************************************************************* + + 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 { + localRead, + runtime, + sendMessage, +} from './ext.js'; + +import { dnr } from './ext-compat.js'; +import { dom } from './dom.js'; + +/******************************************************************************/ + +function renderData(data, depth = 0) { + const indent = ' '.repeat(depth); + if ( Array.isArray(data) ) { + const out = []; + for ( const value of data ) { + out.push(renderData(value, depth)); + } + return out.join('\n'); + } + if ( typeof data !== 'object' || data === null ) { + return `${indent}${data}`; + } + const out = []; + for ( const [ name, value ] of Object.entries(data) ) { + if ( typeof value === 'object' && value !== null ) { + out.push(`${indent}${name}:`); + out.push(renderData(value, depth + 1)); + continue; + } + out.push(`${indent}${name}: ${value}`); + } + return out.join('\n'); +} + +/******************************************************************************/ + +export async function getTroubleshootingInfo(siteMode) { + const manifest = runtime.getManifest(); + const [ + platformInfo, + rulesets, + defaultMode, + userRules, + registerContentScriptsReason, + unregisterContentScriptsReason, + ] = await Promise.all([ + runtime.getPlatformInfo(), + dnr.getEnabledRulesets(), + sendMessage({ what: 'getDefaultFilteringMode' }), + sendMessage({ what: 'getEffectiveUserRules' }), + localRead('$scripting.registerContentScripts'), + localRead('$scripting.unregisterContentScripts'), + ]); + const browser = (( ) => { + const extURL = runtime.getURL(''); + let agent = ''; + if ( extURL.startsWith('moz-extension:') ) { + agent = 'Firefox'; + } else if ( extURL.startsWith('safari-web-extension:') ) { + agent = 'Safari'; + } else if ( /\bEdg\/\b/.test(navigator.userAgent) ) { + agent = 'Edge'; + } else { + agent = 'Chrome'; + } + dom.cl.add('html', agent.toLowerCase()); + if ( /\bMobile\b/.test(navigator.userAgent) ) { + agent += ' Mobile'; + } + const reVersion = new RegExp(`\\b${agent.slice(0,3)}[^/]*/(\\d+)`); + const match = reVersion.exec(navigator.userAgent); + if ( match ) { + agent += ` ${match[1]}`; + } + agent += ` (${platformInfo.os})` + return agent; + })(); + const modes = [ 'no filtering', 'basic', 'optimal', 'complete' ]; + const filtering = {}; + if ( siteMode ) { + filtering.site = `${modes[siteMode]}` + } + filtering.default = `${modes[defaultMode]}`; + const config = { + name: manifest.name, + version: manifest.version, + browser, + filtering, + }; + if ( userRules.length !== 0 ) { + config['user rules'] = userRules.length; + } + config.rulesets = rulesets; + if ( registerContentScriptsReason !== undefined ) { + config.registerContentScripts = registerContentScriptsReason; + } + if ( unregisterContentScriptsReason !== undefined ) { + config.unregisterContentScripts = unregisterContentScriptsReason; + } + return renderData(config); +} diff --git a/platform/mv3/extension/js/ubo-parser.js b/platform/mv3/extension/js/ubo-parser.js new file mode 100644 index 0000000000000..67d16673eb2ab --- /dev/null +++ b/platform/mv3/extension/js/ubo-parser.js @@ -0,0 +1,465 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2014-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import * as sfp from './static-filtering-parser.js'; +import punycode from './punycode.js'; +import redirectResourceMap from './redirect-resources.js'; + +/******************************************************************************/ + +const validResourceTypes = [ + 'main_frame', + 'sub_frame', + 'stylesheet', + 'script', + 'image', + 'font', + 'object', + 'xmlhttprequest', + 'ping', + 'csp_report', + 'media', + 'websocket', + 'webtransport', + 'webbundle', + 'other', +]; + +/******************************************************************************/ + +const validRedirectResources = (( ) => { + const out = new Map(); + for ( const [ name, resource ] of redirectResourceMap ) { + out.set(name, name); + if ( resource.alias === undefined ) { continue; } + if ( typeof resource.alias === 'string' ) { + out.set(resource.alias, name); + continue; + } + if ( Array.isArray(resource.alias) ) { + for ( const alias of resource.alias ) { + out.set(alias, name); + } + } + } + return out; +})(); + +/******************************************************************************/ + +function parseHostnameList(iter) { + const out = { + included: { + good: [], + bad: [], + }, + excluded: { + good: [], + bad: [], + }, + }; + for ( let { hn, not, bad } of iter ) { + bad ||= hn.includes('/') || hn.includes('*'); + const hnAscii = bad === false && hn.startsWith('xn--') + ? punycode.toASCII(hn) + : hn; + const destination = not ? out.excluded : out.included; + if ( bad ) { + destination.bad.push(hnAscii); + } else { + destination.good.push(hnAscii); + } + } + return out; +} + +/******************************************************************************/ + +export function mergeIncludeExclude(rules) { + const includeExcludes = [ + { includeName: 'requestDomains', excludeName: 'excludedRequestDomains' }, + { includeName: 'initiatorDomains', excludeName: 'excludedInitiatorDomains' }, + { includeName: 'resourceTypes', excludeName: 'excludedResourceTypes' }, + { includeName: 'requestMethods', excludeName: 'excludedRequestMethods' }, + ]; + for ( const { includeName, excludeName } of includeExcludes ) { + const out = []; + const distinctRules = new Map(); + for ( const rule of rules ) { + const { id, condition } = rule; + if ( Boolean(condition[includeName]?.length) === false ) { + if ( Boolean(condition[excludeName]?.length) === false ) { + out.push(rule); + continue; + } + } + const included = condition[includeName] || []; + condition[includeName] = undefined; + const excluded = condition[excludeName] || []; + condition[excludeName] = undefined; + rule.id = undefined; + const hash = JSON.stringify(rule); + const details = distinctRules.get(hash) || + { id, included: new Set(), excluded: new Set() }; + if ( details.included.size === 0 && details.excluded.size === 0 ) { + distinctRules.set(hash, details); + } + for ( const hn of included ) { + details.included.add(hn); + } + for ( const hn of excluded ) { + if ( details.included.has(hn) ) { continue; } + details.excluded.add(hn); + } + } + for ( const [ hash, { id, included, excluded } ] of distinctRules ) { + const rule = JSON.parse(hash); + if ( id ) { + rule.id = id; + } + if ( included.size !== 0 ) { + rule.condition[includeName] = Array.from(included); + } + if ( excluded.size !== 0 ) { + rule.condition[excludeName] = Array.from(excluded); + } + out.push(rule); + } + rules = out; + } + return rules; +} + +/******************************************************************************/ + +function parseNetworkFilter(parser) { + if ( parser.isNetworkFilter() === false ) { return; } + if ( parser.hasError() ) { return; } + + const rule = { + action: { type: 'block' }, + condition: { }, + }; + if ( parser.isException() ) { + rule.action.type = 'allow'; + } + + let pattern = parser.getNetPattern(); + if ( parser.isHostnamePattern() ) { + rule.condition.requestDomains = [ pattern ]; + } else if ( parser.isPlainPattern() || parser.isGenericPattern() ) { + if ( parser.isLeftHnAnchored() ) { + pattern = `||${pattern}`; + } else if ( parser.isLeftAnchored() ) { + pattern = `|${pattern}`; + } + if ( parser.isRightAnchored() ) { + pattern = `${pattern}|`; + } + rule.condition.urlFilter = pattern; + } else if ( parser.isRegexPattern() ) { + rule.condition.regexFilter = pattern; + } else if ( parser.isAnyPattern() === false ) { + rule.condition.urlFilter = pattern; + } + + const initiatorDomains = new Set(); + const excludedInitiatorDomains = new Set(); + const requestDomains = new Set(); + const excludedRequestDomains = new Set(); + const requestMethods = new Set(); + const excludedRequestMethods = new Set(); + const resourceTypes = new Set(); + const excludedResourceTypes = new Set(); + + const processResourceType = (resourceType, nodeType) => { + const not = parser.isNegatedOption(nodeType) + if ( validResourceTypes.includes(resourceType) === false ) { + if ( not ) { return; } + } + if ( not ) { + excludedResourceTypes.add(resourceType); + } else { + resourceTypes.add(resourceType); + } + }; + + let priority = 0; + + for ( const type of parser.getNodeTypes() ) { + switch ( type ) { + case sfp.NODE_TYPE_NET_OPTION_NAME_1P: + rule.condition.domainType = parser.isNegatedOption(type) + ? 'thirdParty' + : 'firstParty'; + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_STRICT1P: + case sfp.NODE_TYPE_NET_OPTION_NAME_STRICT3P: + case sfp.NODE_TYPE_NET_OPTION_NAME_BADFILTER: + case sfp.NODE_TYPE_NET_OPTION_NAME_CNAME: + case sfp.NODE_TYPE_NET_OPTION_NAME_EHIDE: + case sfp.NODE_TYPE_NET_OPTION_NAME_GENERICBLOCK: + case sfp.NODE_TYPE_NET_OPTION_NAME_GHIDE: + case sfp.NODE_TYPE_NET_OPTION_NAME_IPADDRESS: + case sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE: + case sfp.NODE_TYPE_NET_OPTION_NAME_REPLACE: + case sfp.NODE_TYPE_NET_OPTION_NAME_SHIDE: + case sfp.NODE_TYPE_NET_OPTION_NAME_URLSKIP: + return; + case sfp.NODE_TYPE_NET_OPTION_NAME_INLINEFONT: + case sfp.NODE_TYPE_NET_OPTION_NAME_INLINESCRIPT: + case sfp.NODE_TYPE_NET_OPTION_NAME_POPUNDER: + case sfp.NODE_TYPE_NET_OPTION_NAME_POPUP: + case sfp.NODE_TYPE_NET_OPTION_NAME_WEBRTC: + processResourceType('', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_3P: + rule.condition.domainType = parser.isNegatedOption(type) + ? 'firstParty' + : 'thirdParty'; + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_ALL: + validResourceTypes.forEach(a => resourceTypes.add(a)); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_CSP: + if ( rule.action.responseHeaders ) { return; } + rule.action.type = 'modifyHeaders'; + rule.action.responseHeaders = [ { + header: 'content-security-policy', + operation: 'append', + value: parser.getNetOptionValue(type), + } ]; + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_CSS: + processResourceType('stylesheet', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_DENYALLOW: { + const { included, excluded } = parseHostnameList( + parser.getNetFilterDenyallowOptionIterator() + ); + if ( excluded.good.length !== 0 || excluded.bad.length !== 0 ) { return; } + if ( included.bad.length !== 0 ) { return; } + if ( included.good.length === 0 ) { return; } + for ( const hn of included.good ) { + excludedRequestDomains.add(hn); + } + break; + } + case sfp.NODE_TYPE_NET_OPTION_NAME_DOC: + processResourceType('main_frame', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_FONT: + processResourceType('font', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_FRAME: + processResourceType('sub_frame', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_FROM: { + const { included, excluded } = parseHostnameList( + parser.getNetFilterFromOptionIterator() + ); + if ( included.good.length === 0 ) { + if ( included.bad.length !== 0 ) { return; } + } + if ( excluded.bad.length !== 0 ) { return; } + for ( const hn of included.good ) { + initiatorDomains.add(hn); + } + for ( const hn of excluded.good ) { + excludedInitiatorDomains.add(hn); + } + break; + } + case sfp.NODE_TYPE_NET_OPTION_NAME_HEADER: { + const details = sfp.parseHeaderValue(parser.getNetOptionValue(type)); + const headerInfo = { + header: details.name, + }; + if ( details.value !== '' ) { + if ( details.isRegex ) { return; } + headerInfo.values = [ details.value ]; + } + rule.condition.responseHeaders = [ headerInfo ]; + break; + } + case sfp.NODE_TYPE_NET_OPTION_NAME_IMAGE: + processResourceType('image', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_IMPORTANT: + priority += 30; + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_MATCHCASE: + rule.condition.isUrlFilterCaseSensitive = true; + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_MEDIA: + processResourceType('media', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_METHOD: { + const value = parser.getNetOptionValue(type); + for ( const method of value.toUpperCase().split('|') ) { + const not = method.charCodeAt(0) === 0x7E /* '~' */; + if ( not ) { + excludedRequestMethods.add(method.slice(1)); + } else { + requestMethods.add(method); + } + } + break; + } + case sfp.NODE_TYPE_NET_OPTION_NAME_OBJECT: + processResourceType('object', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_OTHER: + processResourceType('other', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_PERMISSIONS: + if ( rule.action.responseHeaders ) { return; } + rule.action.type = 'modifyHeaders'; + rule.action.responseHeaders = [ { + header: 'permissions-policy', + operation: 'append', + value: parser.getNetOptionValue(type), + } ]; + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_PING: + processResourceType('ping', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_REASON: + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECT: { + if ( rule.action.type !== 'block' ) { return; } + let value = parser.getNetOptionValue(type); + const match = /:(\d+)$/.exec(value); + if ( match ) { + const subpriority = parseInt(match[1], 10); + priority += Math.min(subpriority, 8); + value = value.slice(0, match.index); + } + if ( validRedirectResources.has(value) === false ) { return; } + rule.action.type = 'redirect'; + rule.action.redirect = { + extensionPath: `/web_accessible_resources/${validRedirectResources.get(value)}`, + }; + priority += 11; + break; + } + case sfp.NODE_TYPE_NET_OPTION_NAME_REMOVEPARAM: { + const details = sfp.parseQueryPruneValue(parser.getNetOptionValue(type)); + if ( details.bad ) { return; } + if ( details.not ) { return; } + if ( details.re ) { return; } + const removeParams = []; + if ( details.name ) { + removeParams.push(details.name); + } + rule.action.type = 'redirect'; + rule.action.redirect = { + transform: { queryTransform: { removeParams } } + }; + break; + } + case sfp.NODE_TYPE_NET_OPTION_NAME_SCRIPT: + processResourceType('script', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_TO: { + const { included, excluded } = parseHostnameList( + parser.getNetFilterToOptionIterator() + ); + if ( included.good.length === 0 ) { + if ( included.bad.length !== 0 ) { return; } + } + if ( excluded.bad.length !== 0 ) { return; } + for ( const hn of included.good ) { + requestDomains.add(hn); + } + for ( const hn of excluded.good ) { + excludedRequestDomains.add(hn); + } + break; + } + case sfp.NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM: + if ( this.processOptionWithValue(parser, type) === false ) { + return this.FILTER_INVALID; + } + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_XHR: + processResourceType('xmlhttprequest', type); + break; + case sfp.NODE_TYPE_NET_OPTION_NAME_WEBSOCKET: + processResourceType('websocket', type); + break; + default: + break; + } + } + if ( initiatorDomains.size !== 0 ) { + rule.condition.initiatorDomains = Array.from(initiatorDomains); + } + if ( excludedInitiatorDomains.size !== 0 ) { + rule.condition.excludedInitiatorDomains = Array.from(excludedInitiatorDomains); + } + if ( requestDomains.size !== 0 ) { + rule.condition.requestDomains = Array.from(requestDomains); + } + if ( excludedRequestDomains.size !== 0 ) { + rule.condition.excludedRequestDomains = Array.from(excludedRequestDomains); + } + if ( requestMethods.size !== 0 ) { + rule.condition.requestMethods = Array.from(requestMethods); + } + if ( excludedRequestMethods.size !== 0 ) { + rule.condition.excludedRequestMethods = Array.from(excludedRequestMethods); + } + if ( resourceTypes.size !== 0 ) { + const types = Array.from(resourceTypes).filter(a => a !== ''); + if ( types.length === 0 ) { return; } + rule.condition.resourceTypes = types; + } + if ( excludedResourceTypes.size !== 0 ) { + if ( resourceTypes.size !== 0 ) { + if ( excludedResourceTypes.size !== 0 ) { return; } + } + rule.condition.excludedResourceTypes = Array.from(excludedResourceTypes); + } + if ( priority !== 0 ) { + rule.priority = priority; + } + return rule; +} + +/******************************************************************************/ + +export function parseFilters(text) { + if ( text.startsWith('---') ) { return; } + if ( text.endsWith('---') ) { return; } + const lines = text.split(/\n/); + if ( lines.some(a => a.startsWith(' ')) ) { return; } + const rules = []; + const parser = new sfp.AstFilterParser({ trustedSource: true }); + for ( const line of lines ) { + parser.parse(line); + if ( parser.isNetworkFilter() === false ) { continue; } + const rule = parseNetworkFilter(parser); + if ( rule === undefined ) { continue; } + rules.push(rule); + } + return mergeIncludeExclude(rules); +} diff --git a/platform/mv3/extension/js/unpicker-ui.js b/platform/mv3/extension/js/unpicker-ui.js new file mode 100644 index 0000000000000..afc9f64bd347d --- /dev/null +++ b/platform/mv3/extension/js/unpicker-ui.js @@ -0,0 +1,164 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { dom, qs$, qsa$ } from './dom.js'; +import { faIconsInit } from './fa-icons.js'; +import { toolOverlay } from './tool-overlay-ui.js'; + +/******************************************************************************/ + +function onMinimizeClicked() { + dom.cl.toggle(dom.root, 'minimized'); +} + +/******************************************************************************/ + +function highlight() { + const selectors = []; + for ( const selectorElem of qsa$('#customFilters .customFilter.on > span.selector') ) { + selectors.push(selectorElem.textContent); + } + if ( selectors.length !== 0 ) { + toolOverlay.postMessage({ + what: 'highlightFromSelector', + selector: selectors.join(','), + scrollTo: true, + }); + } else { + toolOverlay.postMessage({ what: 'unhighlight' }); + } +} + +/******************************************************************************/ + +function onFilterClicked(ev) { + const target = ev.target; + const filterElem = target.closest('.customFilter'); + if ( filterElem === null ) { return; } + const selectorElem = qs$(filterElem, ':scope > span.selector'); + if ( target === selectorElem ) { + if ( dom.cl.has(filterElem, 'on') ) { + dom.cl.remove(filterElem, 'on'); + } else { + dom.cl.remove('.customFilter.on', 'on'); + dom.cl.add(filterElem, 'on'); + } + highlight(); + return; + } + const selector = selectorElem.textContent; + const trashElem = qs$(filterElem, ':scope > span.remove'); + if ( target === trashElem ) { + dom.cl.add(filterElem, 'removed'); + dom.cl.remove(filterElem, 'on'); + toolOverlay.sendMessage({ what: 'removeCustomFilter', + hostname: toolOverlay.url.hostname, + selector, + }).then(( ) => { + autoSelectFilter(); + }); + return; + } + const undoElem = qs$(filterElem, ':scope > span.undo'); + if ( target === undoElem ) { + dom.cl.remove(filterElem, 'removed'); + toolOverlay.sendMessage({ what: 'addCustomFilter', + hostname: toolOverlay.url.hostname, + selector, + }).then(( ) => { + dom.cl.remove('.customFilter.on', 'on'); + dom.cl.add(filterElem, 'on'); + highlight(); + }); + return; + } +} + +/******************************************************************************/ + +function autoSelectFilter() { + let filterElem = qs$('.customFilter.on'); + if ( filterElem !== null ) { return; } + filterElem = qs$('.customFilter:not(.removed)'); + if ( filterElem !== null ) { + dom.cl.add(filterElem, 'on'); + } + highlight(); +} + +/******************************************************************************/ + +function populateFilters(selectors) { + const container = qs$('#customFilters'); + dom.clear(container); + const rowTemplate = qs$('template#customFilterRow'); + for ( const selector of selectors ) { + const row = rowTemplate.content.cloneNode(true); + qs$(row, '.customFilter > span.selector').textContent = selector; + container.append(row); + } + faIconsInit(container); + autoSelectFilter(); +} + +/******************************************************************************/ + +async function startUnpicker() { + const selectors = await toolOverlay.sendMessage({ + what: 'selectorsFromCustomFilters', + hostname: toolOverlay.url.hostname, + }) + if ( selectors.length === 0 ) { + return quitUnpicker(); + } + await toolOverlay.postMessage({ what: 'startTool' }); + await toolOverlay.postMessage({ what: 'uninjectCustomFilters' }); + populateFilters(selectors); + dom.on('#minimize', 'click', onMinimizeClicked); + dom.on('#customFilters', 'click', onFilterClicked); + dom.on('#quit', 'click', quitUnpicker); +} + +/******************************************************************************/ + +async function quitUnpicker() { + await toolOverlay.postMessage({ what: 'injectCustomFilters' }); + toolOverlay.stop(); +} + +/******************************************************************************/ + +function onMessage(msg) { + switch ( msg.what ) { + case 'startTool': + startUnpicker(); + break; + default: + break; + } +} + +/******************************************************************************/ + +// Wait for the content script to establish communication +toolOverlay.start(onMessage); + +/******************************************************************************/ diff --git a/platform/mv3/extension/js/utils.js b/platform/mv3/extension/js/utils.js index cadeaea0b64c3..935d61cfcf2d9 100644 --- a/platform/mv3/extension/js/utils.js +++ b/platform/mv3/extension/js/utils.js @@ -19,20 +19,17 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - -/******************************************************************************/ - -import { browser } from './ext.js'; +import { + browser, + runtime, +} from './ext.js'; /******************************************************************************/ function parsedURLromOrigin(origin) { try { return new URL(origin); - } catch(ex) { + } catch { } } @@ -55,6 +52,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 +72,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); } @@ -94,15 +105,13 @@ const subtractHostnameIters = (itera, iterb) => { /******************************************************************************/ +const matchFromHostname = hn => + hn === '*' || hn === 'all-urls' ? '' : `*://*.${hn}/*`; + const matchesFromHostnames = hostnames => { const out = []; for ( const hn of hostnames ) { - if ( hn === '*' || hn === 'all-urls' ) { - out.length = 0; - out.push(''); - break; - } - out.push(`*://*.${hn}/*`); + out.push(matchFromHostname(hn)); } return out; }; @@ -110,11 +119,11 @@ const matchesFromHostnames = hostnames => { const hostnamesFromMatches = origins => { const out = []; for ( const origin of origins ) { - if ( origin === '' ) { + if ( origin === '' || origin === '*://*/*' ) { out.push('all-urls'); continue; } - const match = /^\*:\/\/(?:\*\.)?([^\/]+)\/\*/.exec(origin); + const match = /^\*:\/\/(?:\*\.)?([^/]+)\/\*/.exec(origin); if ( match === null ) { continue; } out.push(match[1]); } @@ -123,40 +132,81 @@ 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); -}; +// https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/manifest.json/host_permissions#requested_permissions_and_user_prompts +// "Users can grant or revoke host permissions on an ad hoc basis. Therefore, +// most browsers treat host_permissions as optional." -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; } +async function hasBroadHostPermissions() { + return browser.permissions.getAll().then(permissions => + permissions.origins.includes('') || + permissions.origins.includes('*://*/*') + ).catch(( ) => false); +} + +/******************************************************************************/ + +async function gotoURL(url, type) { + const pageURL = new URL(url, runtime.getURL('/')); + const tabs = await browser.tabs.query({ + url: pageURL.href, + windowType: type !== 'popup' ? 'normal' : 'popup' + }); + + if ( Array.isArray(tabs) && tabs.length !== 0 ) { + const { windowId, id } = tabs[0]; + return Promise.all([ + browser.windows.update(windowId, { focused: true }), + browser.tabs.update(id, { active: true }), + ]); + } + + if ( type === 'popup' ) { + return browser.windows.create({ + type: 'popup', + url: pageURL.href, + }); + } + + return browser.tabs.create({ + active: true, + url: pageURL.href, + }); +} + +/******************************************************************************/ + +// Important: We need to sort the arrays for fast comparison +const strArrayEq = (a = [], b = [], sort = true) => { + const alen = a.length; + if ( alen !== b.length ) { return false; } + if ( sort ) { a.sort(); b.sort(); } + for ( let i = 0; i < alen; i++ ) { + if ( a[i] !== b[i] ) { return false; } + } return true; -})(); +}; /******************************************************************************/ export { + broadcastMessage, parsedURLromOrigin, toBroaderHostname, isDescendantHostname, isDescendantHostnameOfIter, intersectHostnameIters, subtractHostnameIters, + matchFromHostname, matchesFromHostnames, hostnamesFromMatches, - ubolLog, + hasBroadHostPermissions, + gotoURL, + strArrayEq, }; diff --git a/platform/mv3/extension/js/zapper-ui.js b/platform/mv3/extension/js/zapper-ui.js new file mode 100644 index 0000000000000..3562f6b362a83 --- /dev/null +++ b/platform/mv3/extension/js/zapper-ui.js @@ -0,0 +1,132 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import { dom } from './dom.js'; +import { toolOverlay } from './tool-overlay-ui.js'; + +/******************************************************************************/ + +function onSvgClicked(ev) { + // If zap mode, highlight element under mouse, this makes the zapper usable + // on touch screens. + toolOverlay.postMessage({ + what: 'zapElementAtPoint', + mx: ev.clientX, + my: ev.clientY, + options: { + stay: true, + highlight: ev.target !== toolOverlay.svgIslands, + }, + }); +} + +/******************************************************************************/ + +const onSvgTouch = (( ) => { + let startX = 0, startY = 0; + let t0 = 0; + return ev => { + if ( ev.type === 'touchstart' ) { + startX = ev.touches[0].screenX; + startY = ev.touches[0].screenY; + t0 = ev.timeStamp; + return; + } + if ( startX === undefined ) { return; } + const stopX = ev.changedTouches[0].screenX; + const stopY = ev.changedTouches[0].screenY; + const distance = Math.sqrt( + Math.pow(stopX - startX, 2) + + Math.pow(stopY - startY, 2) + ); + // Interpret touch events as a tap if: + // - Swipe is not valid; and + // - The time between start and stop was less than 200ms. + const duration = ev.timeStamp - t0; + if ( distance >= 32 || duration >= 200 ) { return; } + onSvgClicked({ + type: 'touch', + target: ev.target, + clientX: ev.changedTouches[0].pageX, + clientY: ev.changedTouches[0].pageY, + }); + ev.preventDefault(); + }; +})(); + +/******************************************************************************/ + +function onKeyPressed(ev) { + // Delete + if ( ev.key === 'Delete' || ev.key === 'Backspace' ) { + toolOverlay.postMessage({ + what: 'zapElementAtPoint', + options: { stay: true }, + }); + return; + } + // Esc + if ( ev.key === 'Escape' || ev.which === 27 ) { + quitZapper(); + return; + } +} + +/******************************************************************************/ + +function startZapper() { + toolOverlay.postMessage({ what: 'startTool' }); + self.addEventListener('keydown', onKeyPressed, true); + dom.on('svg#overlay', 'click', onSvgClicked); + dom.on('svg#overlay', 'touchstart', onSvgTouch, { passive: true }); + dom.on('svg#overlay', 'touchend', onSvgTouch); + dom.on('#quit', 'click', quitZapper ); + dom.on('#pick', 'click', resetZapper ); + toolOverlay.highlightElementUnderMouse(true); +} + +function quitZapper() { + self.removeEventListener('keydown', onKeyPressed, true); + toolOverlay.stop(); +} + +function resetZapper() { + toolOverlay.postMessage({ what: 'unhighlight' }); +} + +/******************************************************************************/ + +function onMessage(msg) { + switch ( msg.what ) { + case 'startTool': + startZapper(); + break; + default: + break; + } +} + +/******************************************************************************/ + +// Wait for the content script to establish communication +toolOverlay.start(onMessage); + +/******************************************************************************/ diff --git a/platform/mv3/extension/lib/codemirror/README.md b/platform/mv3/extension/lib/codemirror/README.md new file mode 100644 index 0000000000000..ac2833e77e7a9 --- /dev/null +++ b/platform/mv3/extension/lib/codemirror/README.md @@ -0,0 +1,9 @@ +Steps to build `cm6.bundle.ubol.min.js` -- command line from repo root: + +- `git submodule init platform/mv3/extension/lib/codemirror/codemirror-ubol` +- `cd platform/mv3/extension/lib/codemirror/codemirror-ubol/` + - We are now in a customized repo forked from +- `npm install` +- `npm run build` +- `cm6.bundle.ubol.min.js` should be in `dist` directory +- This is the origin of the `cm6.bundle.ubol.min.js` in the current directory diff --git a/platform/mv3/extension/lib/codemirror/codemirror-ubol b/platform/mv3/extension/lib/codemirror/codemirror-ubol new file mode 160000 index 0000000000000..0cd9b7a77cd16 --- /dev/null +++ b/platform/mv3/extension/lib/codemirror/codemirror-ubol @@ -0,0 +1 @@ +Subproject commit 0cd9b7a77cd166186ebdb483d6aac82f616685df diff --git a/platform/mv3/extension/lib/codemirror/codemirror.LICENSE b/platform/mv3/extension/lib/codemirror/codemirror.LICENSE new file mode 100644 index 0000000000000..9a91f48619f48 --- /dev/null +++ b/platform/mv3/extension/lib/codemirror/codemirror.LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2018-2021 by Marijn Haverbeke and others + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/platform/mv3/extension/managed_storage.json b/platform/mv3/extension/managed_storage.json index 8571f59dbaef4..85446f2e63cfe 100644 --- a/platform/mv3/extension/managed_storage.json +++ b/platform/mv3/extension/managed_storage.json @@ -2,14 +2,39 @@ "$schema": "http://json-schema.org/draft-03/schema#", "type": "object", "properties": { - "noFiltering": { - "title": "List of domains for which no filtering should occur", + "defaultFiltering": { + "title": "The default filtering mode", + "description": "Can be one of \"none\", \"basic\", \"optimal\", \"complete\".", + "type": "string" + }, + "disabledFeatures": { + "title": "User interface features to disable", + "description": "A list of tokens, each of which correspond to a user interface feature to disable.", "type": "array", "items": { "type": "string" } }, "disableFirstRunPage": { "title": "Disable first run page", "type": "boolean" + }, + "noFiltering": { + "title": "List of domains for which no filtering should occur", + "type": "array", + "items": { "type": "string" } + }, + "rulesets": { + "title": "Rulesets to add/remove", + "description": "Prefix a ruleset id with '+' to add, or '-' to remove. Use '-*' to disable all non-default lists.", + "type": "array", + "items": { "type": "string" } + }, + "showBlockedCount": { + "title": "Enable/disable toolbar icon count badge", + "type": "boolean" + }, + "strictBlockMode": { + "title": "Enable/disable strict blocking", + "type": "boolean" } } } diff --git a/platform/mv3/extension/matched-rules.html b/platform/mv3/extension/matched-rules.html new file mode 100644 index 0000000000000..493c681fada78 --- /dev/null +++ b/platform/mv3/extension/matched-rules.html @@ -0,0 +1,33 @@ + + + + + + +Matched rules + + + + + + + + + + +
+
+ + + + + + + + + diff --git a/platform/mv3/extension/picker-ui.html b/platform/mv3/extension/picker-ui.html new file mode 100644 index 0000000000000..d9e73d5f931ed --- /dev/null +++ b/platform/mv3/extension/picker-ui.html @@ -0,0 +1,56 @@ + + + + + + +uBO Lite Zapper + + + + + + + + + + + + + + + + + + + diff --git a/platform/mv3/extension/popup.html b/platform/mv3/extension/popup.html index 7492469bd0290..eb54d528a9aca 100644 --- a/platform/mv3/extension/popup.html +++ b/platform/mv3/extension/popup.html @@ -4,6 +4,7 @@ + @@ -12,7 +13,8 @@ - + +
­
@@ -25,30 +27,31 @@

_
-
- - - - - cogs -
-
-
-
- -
- - _angle-up +
+ + + bolt + _ + + + eye-slash + _ - - angle-up_ + + eye-open + _ + + + comment-alt + _
-
- -
-

+ +
+ list-altShow matched rules + cogs +
diff --git a/platform/mv3/extension/report.html b/platform/mv3/extension/report.html new file mode 100644 index 0000000000000..cf15492d7f452 --- /dev/null +++ b/platform/mv3/extension/report.html @@ -0,0 +1,70 @@ + + + + + + +uBO Lite — Report + + + + + + + + + + + +
+ +

+

Safari users: Please do not report filter issues at the moment. The declarativeNetRequest engine on stable version of Safari is not yet fully implemented as per specs. As a consequence this leads to many cases of network requests not being blocked.

+

+
+
+

+ +
+
+
+

+
+ +

+

+
+ +

+

+ +

+ +
+
+
+
+

+    
+
+ +
+ + + + + + + + diff --git a/platform/mv3/extension/strictblock.html b/platform/mv3/extension/strictblock.html new file mode 100644 index 0000000000000..9cd2570302a27 --- /dev/null +++ b/platform/mv3/extension/strictblock.html @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + +
+ + +
+

+ +
+ + + + + +
+ +
+ +
+ + + +
+
+ + + + + + + diff --git a/platform/mv3/extension/unpicker-ui.html b/platform/mv3/extension/unpicker-ui.html new file mode 100644 index 0000000000000..3402f0267c622 --- /dev/null +++ b/platform/mv3/extension/unpicker-ui.html @@ -0,0 +1,40 @@ + + + + + + +uBO Lite Zapper + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/mv3/extension/zapper-ui.html b/platform/mv3/extension/zapper-ui.html new file mode 100644 index 0000000000000..7e51230e18cb0 --- /dev/null +++ b/platform/mv3/extension/zapper-ui.html @@ -0,0 +1,32 @@ + + + + + + +uBO Lite Zapper + + + + + + + + + + + + + + + diff --git a/platform/mv3/firefox/background.html b/platform/mv3/firefox/background.html deleted file mode 100644 index 58e9c5e17757e..0000000000000 --- a/platform/mv3/firefox/background.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - -uBlock Origin Background Page - - - - - diff --git a/platform/mv3/firefox/manifest.json b/platform/mv3/firefox/manifest.json index 723ef0fc8ba5b..444b3f52004bd 100644 --- a/platform/mv3/firefox/manifest.json +++ b/platform/mv3/firefox/manifest.json @@ -15,11 +15,19 @@ }, "browser_specific_settings": { "gecko": { - "id": "uBOLite@raymondhill.net", - "strict_min_version": "114.0" + "id": "uBOLiteRedux@raymondhill.net", + "strict_min_version": "128.0" }, "gecko_android": { - "strict_min_version": "114.0" + "strict_min_version": "128.0" + } + }, + "commands": { + "enter-zapper-mode": { + "description": "__MSG_zapperTipEnter__" + }, + "enter-picker-mode": { + "description": "__MSG_pickerTipEnter__" } }, "declarative_net_request": { @@ -35,11 +43,12 @@ "128": "img/icon_128.png" }, "manifest_version": 3, - "name": "__MSG_extName__", + "name": "uBO Lite", "options_ui": { + "open_in_tab": true, "page": "dashboard.html" }, - "optional_permissions": [ + "host_permissions": [ "" ], "permissions": [ @@ -50,5 +59,38 @@ ], "short_name": "uBO Lite", "version": "1.0", - "web_accessible_resources": [] + "web_accessible_resources": [ + { + "resources": [ + "/strictblock.html" + ], + "matches": [ + "" + ] + }, + { + "resources": [ + "/zapper-ui.html" + ], + "matches": [ + "" + ] + }, + { + "resources": [ + "/picker-ui.html" + ], + "matches": [ + "" + ] + }, + { + "resources": [ + "/unpicker-ui.html" + ], + "matches": [ + "" + ] + } + ] } diff --git a/platform/mv3/firefox/patch-ruleset.js b/platform/mv3/firefox/patch-ruleset.js new file mode 100644 index 0000000000000..a8bd25c1b6f72 --- /dev/null +++ b/platform/mv3/firefox/patch-ruleset.js @@ -0,0 +1,30 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +export function patchRuleset(ruleset) { + const out = []; + for ( const rule of ruleset ) { + const condition = rule.condition; + if ( Array.isArray(condition.responseHeaders) ) { continue; } + out.push(rule); + } + return out; +} diff --git a/platform/mv3/make-rulesets.js b/platform/mv3/make-rulesets.js index fd842db38eaa5..2a1e3d94a268f 100644 --- a/platform/mv3/make-rulesets.js +++ b/platform/mv3/make-rulesets.js @@ -19,19 +19,23 @@ 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, + mergeRules, +} from './js/static-dnr-filtering.js'; +import { execSync } from 'node:child_process'; import fs from 'fs/promises'; -import https from 'https'; import path from 'path'; import process from 'process'; -import { 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'; /******************************************************************************/ @@ -60,14 +64,15 @@ const rulesetDir = `${outputDir}/rulesets`; const scriptletDir = `${rulesetDir}/scripting`; const env = [ platform, + 'native_css_has', 'mv3', 'ublock', 'ubol', 'user_stylesheet', ]; -if ( platform !== 'firefox' ) { - env.push('native_css_has'); +if ( platform === 'edge' ) { + env.push('chromium'); } /******************************************************************************/ @@ -85,58 +90,72 @@ const uidint32 = (s) => { return parseInt(h,16) & 0x7FFFFFFF; }; -const hnSort = (a, b) => - a.split('.').reverse().join('.').localeCompare( - b.split('.').reverse().join('.') - ); - /******************************************************************************/ +const consoleLog = console.log; const stdOutput = []; -const log = (text, silent = false) => { +const log = (text, silent = true) => { stdOutput.push(text); if ( silent === false ) { - console.log(text); + consoleLog(text); } }; +console.log = log; + +const logProgress = text => { + process?.stdout?.clearLine?.(); + process?.stdout?.cursorTo?.(0); + process?.stdout?.write?.(text.length > 120 ? `${text.slice(0, 119)}… ` : `${text} `); +}; + /******************************************************************************/ -const urlToFileName = url => { - return url +async function fetchText(url, cacheDir) { + logProgress(`Reading locally cached ${url}`); + const fname = url .replace(/^https?:\/\//, '') - .replace(/\//g, '_') - ; -}; + .replace(/\//g, '_');(url); + const content = await fs.readFile( + `${cacheDir}/${fname}`, + { encoding: 'utf8' } + ).catch(( ) => { }); + if ( content !== undefined ) { + log(`\tFetched local ${url}`); + return { url, content }; + } + logProgress(`Fetching remote ${url}`); + log(`\tFetching remote ${url}`); + const response = await fetch(url).catch(( ) => { }); + if ( response === undefined ) { + return { url, error: `Fetching failed: ${url}` }; + } + let text; + if ( response.ok ) { + text = await response.text().catch(( ) => { }); + } else { + text = await fallbackFetchText(url).catch(( ) => { }); + } + if ( text === undefined ) { + return { url, error: `Fetching text content failed: ${url}` }; + } + writeFile(`${cacheDir}/${fname}`, text); + return { url, content: text }; +} -const fetchText = (url, cacheDir) => { - return new Promise((resolve, reject) => { - const fname = urlToFileName(url); - fs.readFile(`${cacheDir}/${fname}`, { encoding: 'utf8' }).then(content => { - log(`\tFetched local ${url}`); - resolve({ url, content }); - }).catch(( ) => { - log(`\tFetching remote ${url}`); - https.get(url, response => { - const data = []; - response.on('data', chunk => { - data.push(chunk.toString()); - }); - response.on('end', ( ) => { - const content = data.join(''); - try { - writeFile(`${cacheDir}/${fname}`, content); - } catch (ex) { - } - resolve({ url, content }); - }); - }).on('error', error => { - reject(error); - }); - }); - }); -}; +async function fallbackFetchText(url) { + const match = /^https:\/\/raw\.githubusercontent\.com\/([^/]+)\/([^/]+)\/master\/([^?]+)/.exec(url); + if ( match === null ) { return; } + logProgress(`\tGitHub CLI-fetching remote ${url}`); + // https://docs.github.com/en/rest/repos/contents + const content = execSync(`gh api \ + -H "Accept: application/vnd.github.raw+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + /repos/${match[1]}/${match[2]}/contents/${match[3]} \ + `, { encoding: 'utf8' }); + return content; +} /******************************************************************************/ @@ -165,6 +184,53 @@ const rulesetDetails = []; const scriptletStats = new Map(); const genericDetails = new Map(); const requiredRedirectResources = new Set(); +let networkBad = new Set(); + +// This will be used to sign our inserted `!#trusted on` directives +const secret = createHash('sha256').update(randomBytes(16)).digest('hex').slice(0,16); +log(`Secret: ${secret}`, false); + +/******************************************************************************/ + +const restrSeparator = '(?:[^%.0-9a-z_-]|$)'; + +const rePatternFromUrlFilter = s => { + let anchor = 0b000; + if ( s.startsWith('||') ) { + anchor = 0b100; + s = s.slice(2); + } else if ( s.startsWith('|') ) { + anchor = 0b010; + s = s.slice(1); + } + if ( s.endsWith('|') ) { + anchor |= 0b001; + s = s.slice(0, -1); + } + let reStr = s.replace(rePatternFromUrlFilter.rePlainChars, '\\$&') + .replace(rePatternFromUrlFilter.reSeparators, restrSeparator) + .replace(rePatternFromUrlFilter.reDanglingAsterisks, '') + .replace(rePatternFromUrlFilter.reAsterisks, '\\S*?'); + if ( anchor & 0b100 ) { + reStr = ( + reStr.startsWith('\\.') ? + rePatternFromUrlFilter.restrHostnameAnchor2 : + rePatternFromUrlFilter.restrHostnameAnchor1 + ) + reStr; + } else if ( anchor & 0b010 ) { + reStr = '^' + reStr; + } + if ( anchor & 0b001 ) { + reStr += '$'; + } + return reStr; +}; +rePatternFromUrlFilter.rePlainChars = /[.+?${}()|[\]\\]/g; +rePatternFromUrlFilter.reSeparators = /\^/g; +rePatternFromUrlFilter.reDanglingAsterisks = /^\*+|\*+$/g; +rePatternFromUrlFilter.reAsterisks = /\*+/g; +rePatternFromUrlFilter.restrHostnameAnchor1 = '^[a-z-]+://(?:[^/?#]+\\.)?'; +rePatternFromUrlFilter.restrHostnameAnchor2 = '^[a-z-]+://(?:[^/?#]+)?'; /******************************************************************************/ @@ -186,34 +252,33 @@ async function fetchList(assetDetails) { continue; } fetchedURLs.add(part.url); - if ( part.url.startsWith('https://ublockorigin.github.io/uAssets/filters/') ) { - newParts.push(`!#trusted on ${assetDetails.secret}`); + if ( + assetDetails.trusted || + part.url.startsWith('https://ublockorigin.github.io/uAssets/filters/') + ) { + newParts.push(`!#trusted on ${secret}`); } newParts.push( fetchText(part.url, cacheDir).then(details => { - const { url } = details; + const { url, error } = details; + if ( error !== undefined ) { return details; } const content = details.content.trim(); - if ( typeof content === 'string' && content !== '' ) { - if ( - content.startsWith('<') === false || - content.endsWith('>') === false - ) { - return { url, content }; - } + if ( content === '' || /^<.*>$/.test(content) ) { + return { url, error: `Bad content: ${url}` }; } - log(`No valid content for ${details.name}`); - return { url, content: '' }; + return { url, content }; }) ); - newParts.push(`!#trusted off ${assetDetails.secret}`); + newParts.push(`!#trusted off ${secret}`); } + if ( parts.some(v => typeof v === 'object' && v.error) ) { return; } parts = await Promise.all(newParts); parts = sfp.utils.preparser.expandIncludes(parts, env); } const text = parts.join('\n'); if ( text === '' ) { - log('No filterset found'); + log('No filterset found', false); } return text; } @@ -228,7 +293,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 +301,36 @@ 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 && - isRedirect(rule) === false && - isModifyHeaders(rule) === false && - isRemoveparam(rule) === false; + rule.action !== undefined && ( + rule.action.type === 'block' || + rule.action.type === 'allow' || + rule.action.type === 'allowAllRequests' + ); + +const isURLSkip = rule => + isUnsupported(rule) === false && + rule.action !== undefined && + rule.action.type === 'urlskip'; + +/******************************************************************************/ + +async function patchRuleset(ruleset) { + return import(`./${platform}/patch-ruleset.js`).then(module => { + return module.patchRuleset(ruleset) + }).catch(( ) => { + return ruleset; + }); +} /******************************************************************************/ @@ -307,6 +389,23 @@ function pruneHostnameArray(hostnames) { * */ function toJSONRuleset(ruleset) { + const nodupProps = [ 'domains', 'excludedDomains', 'requestDomains', 'excludedRequestDomains', 'initiatorDomains', 'excludedInitiatorDomains' ]; + for ( const { condition } of ruleset ) { + if ( condition === undefined ) { continue; } + for ( const prop of nodupProps ) { + if ( condition[prop] === undefined ) { continue; } + condition[prop] = Array.from(new Set(condition[prop])); + } + } + const sortProps = [ 'requestDomains', 'initiatorDomains', 'domains' ]; + ruleset.sort((a, b) => { + let aLen = 0, bLen = 0; + for ( const prop of sortProps ) { + aLen += a.condition[prop]?.length ?? 0; + bLen += b.condition[prop]?.length ?? 0; + } + return bLen - aLen; + }); const replacer = (k, v) => { if ( k.startsWith('_') ) { return; } if ( Array.isArray(v) ) { @@ -323,7 +422,9 @@ function toJSONRuleset(ruleset) { }; const indent = ruleset.length > 10 ? undefined : 1; const out = []; + let id = 1; for ( const rule of ruleset ) { + rule.id = id++; out.push(JSON.stringify(rule, replacer, indent)); } return `[\n${out.join(',\n')}\n]\n`; @@ -331,6 +432,69 @@ function toJSONRuleset(ruleset) { /******************************************************************************/ +function toStrictBlockRule(rule, out) { + if ( rule.action.type !== 'block' ) { return; } + const { condition } = rule; + if ( condition === undefined ) { return; } + if ( condition.domainType ) { return; } + if ( condition.excludedResourceTypes ) { return; } + if ( condition.requestMethods ) { return; } + if ( condition.excludedRequestMethods ) { return; } + if ( condition.responseHeaders ) { return; } + if ( condition.excludedResponseHeaders ) { return; } + if ( condition.initiatorDomains ) { return; } + if ( condition.excludedInitiatorDomains ) { return; } + const { resourceTypes } = condition; + if ( resourceTypes === undefined ) { + if ( condition.requestDomains === undefined ) { return; } + } else if ( resourceTypes.includes('main_frame') === false ) { + return; + } + let regexFilter; + if ( condition.urlFilter ) { + regexFilter = rePatternFromUrlFilter(condition.urlFilter); + } else if ( condition.regexFilter ) { + regexFilter = condition.regexFilter; + } else { + regexFilter = '^https?://.*'; + } + if ( regexFilter.startsWith('^') === false ) { + regexFilter = `^.*${regexFilter}`; + } + if ( + regexFilter.endsWith('$') === false && + regexFilter.endsWith('.*') === false && + regexFilter.endsWith('.+') === false + ) { + regexFilter = `${regexFilter}.*`; + } + const strictBlockRule = out.get(regexFilter) || { + action: { + type: 'redirect', + redirect: { + regexSubstitution: `/strictblock.html#\\0`, + }, + }, + condition: { + regexFilter, + resourceTypes: [ 'main_frame' ], + }, + priority: 29, + }; + if ( condition.requestDomains ) { + strictBlockRule.condition.requestDomains ??= []; + strictBlockRule.condition.requestDomains.push(...condition.requestDomains); + } + if ( condition.excludedRequestDomains ) { + strictBlockRule.condition.excludedRequestDomains ??= []; + strictBlockRule.condition.excludedRequestDomains.push(...condition.excludedRequestDomains); + } + out.set(regexFilter, strictBlockRule); +} +toStrictBlockRule.ruleId = 1; + +/******************************************************************************/ + async function processNetworkFilters(assetDetails, network) { const { ruleset: rules } = network; log(`Input filter count: ${network.filterCount}`); @@ -360,21 +524,26 @@ async function processNetworkFilters(assetDetails, network) { } } - const plainGood = rules.filter(rule => isGood(rule) && isRegex(rule) === false); + const plainGood = await patchRuleset( + 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 = await patchRuleset( + rules.filter(rule => isSafe(rule) && isRegex(rule)) + ); log(`\tMaybe good (regexes): ${regexes.length}`); - const redirects = rules.filter(rule => - isUnsupported(rule) === false && - isRedirect(rule) + const redirects = await patchRuleset( + rules.filter(rule => + isUnsupported(rule) === false && + isRedirect(rule) + ) ); redirects.forEach(rule => { if ( rule.action.redirect.extensionPath === undefined ) { return; } @@ -384,59 +553,118 @@ async function processNetworkFilters(assetDetails, network) { }); log(`\tredirect=: ${redirects.length}`); - const removeparamsGood = rules.filter(rule => - isUnsupported(rule) === false && isRemoveparam(rule) + const removeparamsGood = await patchRuleset( + rules.filter(rule => + isUnsupported(rule) === false && isRemoveparam(rule) + ) ); - const removeparamsBad = rules.filter(rule => - isUnsupported(rule) && isRemoveparam(rule) + const removeparamsBad = await patchRuleset( + rules.filter(rule => + isUnsupported(rule) && isRemoveparam(rule) + ) ); log(`\tremoveparams= (accepted/discarded): ${removeparamsGood.length}/${removeparamsBad.length}`); - const modifyHeaders = rules.filter(rule => - isUnsupported(rule) === false && - isModifyHeaders(rule) + const modifyHeaders = await patchRuleset( + rules.filter(rule => + isUnsupported(rule) === false && + isModifyHeaders(rule) + ) ); log(`\tmodifyHeaders=: ${modifyHeaders.length}`); + const urlskips = new Map(); + for ( const rule of rules ) { + if ( isURLSkip(rule) === false ) { continue; } + if ( rule.__modifierAction !== 0 ) { continue; } + const { condition } = rule; + if ( condition.resourceTypes ) { + if ( condition.resourceTypes.includes('main_frame') === false ) { + continue; + } + } + const { urlFilter, regexFilter, requestDomains } = condition; + let re; + if ( urlFilter !== undefined ) { + re = rePatternFromUrlFilter(urlFilter); + } else if ( regexFilter !== undefined ) { + re = regexFilter; + } else { + re = '^'; + } + const rawSteps = rule.__modifierValue; + const steps = rawSteps.includes(' ') && rawSteps.split(/ +/) || [ rawSteps ]; + const keyEntry = { + re, + c: condition.isUrlFilterCaseSensitive, + steps, + } + const key = JSON.stringify(keyEntry); + let actualEntry = urlskips.get(key); + if ( actualEntry === undefined ) { + urlskips.set(key, keyEntry); + actualEntry = keyEntry; + } + if ( requestDomains !== undefined ) { + if ( actualEntry.hostnames === undefined ) { + actualEntry.hostnames = []; + } + actualEntry.hostnames.push(...requestDomains); + } + } + log(`\turlskip=: ${urlskips.size}`); + const bad = rules.filter(rule => isUnsupported(rule) ); log(`\tUnsupported: ${bad.length}`); log(bad.map(rule => rule._error.map(v => `\t\t${v}`)).join('\n'), true); - writeFile( - `${rulesetDir}/main/${assetDetails.id}.json`, + writeFile(`${rulesetDir}/main/${assetDetails.id}.json`, toJSONRuleset(plainGood) ); if ( regexes.length !== 0 ) { - writeFile( - `${rulesetDir}/regex/${assetDetails.id}.json`, + writeFile(`${rulesetDir}/regex/${assetDetails.id}.json`, toJSONRuleset(regexes) ); } if ( removeparamsGood.length !== 0 ) { - writeFile( - `${rulesetDir}/removeparam/${assetDetails.id}.json`, + writeFile(`${rulesetDir}/removeparam/${assetDetails.id}.json`, toJSONRuleset(removeparamsGood) ); } if ( redirects.length !== 0 ) { - writeFile( - `${rulesetDir}/redirect/${assetDetails.id}.json`, + writeFile(`${rulesetDir}/redirect/${assetDetails.id}.json`, toJSONRuleset(redirects) ); } if ( modifyHeaders.length !== 0 ) { - writeFile( - `${rulesetDir}/modify-headers/${assetDetails.id}.json`, + writeFile(`${rulesetDir}/modify-headers/${assetDetails.id}.json`, toJSONRuleset(modifyHeaders) ); } + const strictBlocked = new Map(); + for ( const rule of plainGood ) { + toStrictBlockRule(rule, strictBlocked); + } + if ( strictBlocked.size !== 0 ) { + mergeRules(strictBlocked, 'requestDomains'); + writeFile(`${rulesetDir}/strictblock/${assetDetails.id}.json`, + toJSONRuleset(Array.from(strictBlocked.values())) + ); + } + + if ( urlskips.size !== 0 ) { + writeFile(`${rulesetDir}/urlskip/${assetDetails.id}.json`, + JSON.stringify(Array.from(urlskips.values()), null, 1) + ); + } + return { total: rules.length, plain: plainGood.length, @@ -446,6 +674,8 @@ async function processNetworkFilters(assetDetails, network) { removeparam: removeparamsGood.length, redirect: redirects.length, modifyHeaders: modifyHeaders.length, + strictblock: strictBlocked.size, + urlskip: urlskips.size, }; } @@ -490,61 +720,128 @@ function loadAllSourceScriptlets() { /******************************************************************************/ -async function processGenericCosmeticFilters(assetDetails, bucketsMap, exceptionSet) { - if ( bucketsMap === undefined ) { return 0; } - if ( exceptionSet ) { - for ( const [ hash, selectors ] of bucketsMap ) { - let i = selectors.length; - while ( i-- ) { - const selector = selectors[i]; - if ( exceptionSet.has(selector) === false ) { continue; } - selectors.splice(i, 1); - //log(`\tRemoving excepted generic filter ##${selector}`); +// http://www.cse.yorku.ca/~oz/hash.html#djb2 +// Must mirror content script surveyor's version + +async function processGenericCosmeticFilters( + assetDetails, + selectorList, + exceptionList, + declarativeMap +) { + const exceptionSet = new Set( + exceptionList && + exceptionList.filter(a => a.key !== undefined).map(a => a.selector) + ); + + const genericSelectorMap = new Map(); + if ( selectorList ) { + for ( const { key, selector } of selectorList ) { + if ( key === undefined ) { continue; } + if ( exceptionSet.has(selector) ) { continue; } + const type = key.charCodeAt(0); + const hash = hashFromStr(type, key.slice(1)); + const selectors = genericSelectorMap.get(hash); + if ( selectors === undefined ) { + genericSelectorMap.set(hash, selector) + } else { + genericSelectorMap.set(hash, `${selectors},\n${selector}`) } - if ( selectors.length === 0 ) { - bucketsMap.delete(hash); + } + } + + // Specific exceptions + const genericExceptionSieve = new Set(); + const genericExceptionMap = new Map(); + if ( declarativeMap ) { + for ( const [ exception, details ] of declarativeMap ) { + if ( details.rejected ) { continue; } + if ( details.key === undefined ) { continue; } + if ( details.matches !== undefined ) { continue; } + if ( details.excludeMatches === undefined ) { continue; } + const type = details.key.charCodeAt(0); + const hash = hashFromStr(type, details.key.slice(1)); + genericExceptionSieve.add(hash); + for ( const hn of details.excludeMatches ) { + const exceptions = genericExceptionMap.get(hn); + if ( exceptions === undefined ) { + genericExceptionMap.set(hn, exception); + } else { + genericExceptionMap.set(hn, `${exceptions}\n${exception}`); + } } } } - if ( bucketsMap.size === 0 ) { return 0; } - const bucketsList = Array.from(bucketsMap); - const count = bucketsList.reduce((a, v) => a += v[1].length, 0); - if ( count === 0 ) { return 0; } - const selectorLists = bucketsList.map(v => [ v[0], v[1].join(',') ]); - const originalScriptletMap = await loadAllSourceScriptlets(); + if ( genericSelectorMap.size === 0 ) { + if ( genericExceptionMap.size === 0 ) { return 0; } + } + + const originalScriptletMap = await loadAllSourceScriptlets(); let patchedScriptlet = originalScriptletMap.get('css-generic').replace( '$rulesetId$', assetDetails.id ); patchedScriptlet = safeReplace(patchedScriptlet, /\bself\.\$genericSelectorMap\$/, - `${JSON.stringify(selectorLists, scriptletJsonReplacer)}` + `${JSON.stringify(genericSelectorMap, scriptletJsonReplacer)}` + ); + patchedScriptlet = safeReplace(patchedScriptlet, + /\bself\.\$genericExceptionSieve\$/, + `${JSON.stringify(genericExceptionSieve, scriptletJsonReplacer)}` + ); + patchedScriptlet = safeReplace(patchedScriptlet, + /\bself\.\$genericExceptionMap\$/, + `${JSON.stringify(genericExceptionMap, scriptletJsonReplacer)}` ); - writeFile( - `${scriptletDir}/generic/${assetDetails.id}.js`, + writeFile(`${scriptletDir}/generic/${assetDetails.id}.js`, patchedScriptlet ); - log(`CSS-generic: ${count} plain CSS selectors`); + log(`CSS-generic: ${genericExceptionSieve.size} specific CSS exceptions`); + log(`CSS-generic: ${genericSelectorMap.size} plain CSS selectors`); - return count; + return genericSelectorMap.size + genericExceptionSieve.size; } +const hashFromStr = (type, s) => { + const len = s.length; + const step = len + 7 >>> 3; + let hash = (type << 5) + type ^ len; + for ( let i = 0; i < len; i += step ) { + hash = (hash << 5) + hash ^ s.charCodeAt(i); + } + return hash & 0xFFFFFF; +}; + /******************************************************************************/ -async function processGenericHighCosmeticFilters(assetDetails, selectorSet, exceptionSet) { - if ( selectorSet === undefined ) { return 0; } - if ( exceptionSet ) { - for ( const selector of selectorSet ) { - if ( exceptionSet.has(selector) === false ) { continue; } - selectorSet.delete(selector); - //log(`\tRemoving excepted generic filter ##${selector}`); +async function processGenericHighCosmeticFilters( + assetDetails, + genericSelectorList, + genericExceptionList +) { + if ( genericSelectorList === undefined ) { return 0; } + const genericSelectorSet = new Set( + genericSelectorList + .filter(a => a.key === undefined) + .map(a => a.selector) + ); + // https://github.com/uBlockOrigin/uBOL-home/issues/365 + if ( genericExceptionList ) { + for ( const entry of genericExceptionList ) { + if ( entry.key !== undefined ) { continue; } + globalHighlyGenericExceptionSet.add(entry.selector); } } - if ( selectorSet.size === 0 ) { return 0; } - const selectorLists = Array.from(selectorSet).sort().join(',\n'); + for ( const selector of globalHighlyGenericExceptionSet ) { + if ( genericSelectorSet.has(selector) === false ) { continue; } + genericSelectorSet.delete(selector); + log(`\tRemoving excepted highly generic filter ##${selector}`); + } + if ( genericSelectorSet.size === 0 ) { return 0; } + const selectorLists = Array.from(genericSelectorSet).sort().join(',\n'); const originalScriptletMap = await loadAllSourceScriptlets(); let patchedScriptlet = originalScriptletMap.get('css-generichigh').replace( @@ -556,16 +853,17 @@ async function processGenericHighCosmeticFilters(assetDetails, selectorSet, exce selectorLists ); - writeFile( - `${scriptletDir}/generichigh/${assetDetails.id}.css`, + writeFile(`${scriptletDir}/generichigh/${assetDetails.id}.css`, patchedScriptlet ); - log(`CSS-generic-high: ${selectorSet.size} plain CSS selectors`); + log(`CSS-generic-high: ${genericSelectorSet.size} plain CSS selectors`); - return selectorSet.size; + return genericSelectorSet.size; } +const globalHighlyGenericExceptionSet = new Set(); + /******************************************************************************/ // This merges selectors which are used by the same hostnames @@ -626,14 +924,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; } @@ -665,22 +959,33 @@ const scriptletJsonReplacer = (k, v) => { /******************************************************************************/ function argsMap2List(argsMap, hostnamesMap) { - const argsList = []; + const argsList = [ '' ]; const indexMap = new Map(); for ( const [ id, details ] of argsMap ) { indexMap.set(id, argsList.length); argsList.push(details); } + const argsSeqs = [ 0 ]; + const argsSeqsIndices = new Map(); for ( const [ hn, ids ] of hostnamesMap ) { + const seqKey = JSON.stringify(ids); + if ( argsSeqsIndices.has(seqKey) ) { + hostnamesMap.set(hn, argsSeqsIndices.get(seqKey)); + continue; + } + const seqIndex = argsSeqs.length; + argsSeqsIndices.set(seqKey, seqIndex); + hostnamesMap.set(hn, seqIndex); if ( typeof ids === 'number' ) { - hostnamesMap.set(hn, indexMap.get(ids)); + argsSeqs.push(indexMap.get(ids)); continue; } for ( let i = 0; i < ids.length; i++ ) { - ids[i] = indexMap.get(ids[i]); + argsSeqs.push(-indexMap.get(ids[i])); } + argsSeqs[argsSeqs.length-1] = -argsSeqs[argsSeqs.length-1]; } - return argsList; + return { argsList, argsSeqs }; } /******************************************************************************/ @@ -704,38 +1009,21 @@ async function processCosmeticFilters(assetDetails, mapin) { const argsMap = domainBasedEntries.map(entry => [ entry[0], - { - a: entry[1].a ? entry[1].a.join(',\n') : undefined, - n: entry[1].n - } + entry[1].a ? entry[1].a.join('\n') : undefined, ]); const hostnamesMap = new Map(); + let hasEntities = false; for ( const [ id, details ] of domainBasedEntries ) { - if ( details.y === undefined ) { continue; } - scriptletHostnameToIdMap(details.y, id, hostnamesMap); - } - const argsList = argsMap2List(argsMap, hostnamesMap); - const entitiesMap = new Map(); - for ( const [ hn, details ] of hostnamesMap ) { - if ( hn.endsWith('.*') === false ) { continue; } - hostnamesMap.delete(hn); - entitiesMap.set(hn.slice(0, -2), details); - } - - // Extract exceptions from argsList, simplify argsList entries - const exceptionsMap = new Map(); - for ( let i = 0; i < argsList.length; i++ ) { - const details = argsList[i]; + if ( details.y ) { + scriptletHostnameToIdMap(details.y, id, hostnamesMap); + hasEntities ||= details.y.some(a => a.endsWith('.*')); + } if ( details.n ) { - for ( const hn of details.n ) { - if ( exceptionsMap.has(hn) === false ) { - exceptionsMap.set(hn, []); - } - exceptionsMap.get(hn).push(i); - } + scriptletHostnameToIdMap(details.n.map(a => `~${a}`), id, hostnamesMap); + hasEntities ||= details.n.some(a => a.endsWith('.*')); } - argsList[i] = details.a; } + const { argsList, argsSeqs } = argsMap2List(argsMap, hostnamesMap); const originalScriptletMap = await loadAllSourceScriptlets(); let patchedScriptlet = originalScriptletMap.get('css-specific').replace( @@ -747,16 +1035,16 @@ async function processCosmeticFilters(assetDetails, mapin) { `${JSON.stringify(argsList, scriptletJsonReplacer)}` ); patchedScriptlet = safeReplace(patchedScriptlet, - /\bself\.\$hostnamesMap\$/, - `${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}` + /\bself\.\$argsSeqs\$/, + `${JSON.stringify(argsSeqs, scriptletJsonReplacer)}` ); patchedScriptlet = safeReplace(patchedScriptlet, - /\bself\.\$entitiesMap\$/, - `${JSON.stringify(entitiesMap, scriptletJsonReplacer)}` + /\bself\.\$hostnamesMap\$/, + `${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}` ); patchedScriptlet = safeReplace(patchedScriptlet, - /\bself\.\$exceptionsMap\$/, - `${JSON.stringify(exceptionsMap, scriptletJsonReplacer)}` + 'self.$hasEntities$', + JSON.stringify(hasEntities) ); writeFile(`${scriptletDir}/specific/${assetDetails.id}.js`, patchedScriptlet); generatedFiles.push(`${assetDetails.id}`); @@ -764,10 +1052,9 @@ async function processCosmeticFilters(assetDetails, mapin) { if ( generatedFiles.length !== 0 ) { log(`CSS-specific: ${mapin.size} distinct filters`); log(`\tCombined into ${hostnamesMap.size} distinct hostnames`); - log(`\tCombined into ${entitiesMap.size} distinct entities`); } - return hostnamesMap.size + entitiesMap.size; + return hostnamesMap.size; } /******************************************************************************/ @@ -792,38 +1079,21 @@ async function processDeclarativeCosmeticFilters(assetDetails, mapin) { const argsMap = contentArray.map(entry => [ entry[0], - { - a: entry[1].a, - n: entry[1].n, - } + entry[1].a ? entry[1].a.join('\n') : undefined, ]); const hostnamesMap = new Map(); + let hasEntities = false; for ( const [ id, details ] of contentArray ) { - if ( details.y === undefined ) { continue; } - scriptletHostnameToIdMap(details.y, id, hostnamesMap); - } - const argsList = argsMap2List(argsMap, hostnamesMap); - const entitiesMap = new Map(); - for ( const [ hn, details ] of hostnamesMap ) { - if ( hn.endsWith('.*') === false ) { continue; } - hostnamesMap.delete(hn); - entitiesMap.set(hn.slice(0, -2), details); - } - - // Extract exceptions from argsList, simplify argsList entries - const exceptionsMap = new Map(); - for ( let i = 0; i < argsList.length; i++ ) { - const details = argsList[i]; + if ( details.y ) { + scriptletHostnameToIdMap(details.y, id, hostnamesMap); + hasEntities ||= details.y.some(a => a.endsWith('.*')); + } if ( details.n ) { - for ( const hn of details.n ) { - if ( exceptionsMap.has(hn) === false ) { - exceptionsMap.set(hn, []); - } - exceptionsMap.get(hn).push(i); - } + scriptletHostnameToIdMap(details.n.map(a => `~${a}`), id, hostnamesMap); + hasEntities ||= details.n.some(a => a.endsWith('.*')); } - argsList[i] = details.a; } + const { argsList, argsSeqs } = argsMap2List(argsMap, hostnamesMap); const originalScriptletMap = await loadAllSourceScriptlets(); let patchedScriptlet = originalScriptletMap.get('css-declarative').replace( @@ -835,26 +1105,25 @@ async function processDeclarativeCosmeticFilters(assetDetails, mapin) { `${JSON.stringify(argsList, scriptletJsonReplacer)}` ); patchedScriptlet = safeReplace(patchedScriptlet, - /\bself\.\$hostnamesMap\$/, - `${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}` + /\bself\.\$argsSeqs\$/, + `${JSON.stringify(argsSeqs, scriptletJsonReplacer)}` ); patchedScriptlet = safeReplace(patchedScriptlet, - /\bself\.\$entitiesMap\$/, - `${JSON.stringify(entitiesMap, scriptletJsonReplacer)}` + /\bself\.\$hostnamesMap\$/, + `${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}` ); patchedScriptlet = safeReplace(patchedScriptlet, - /\bself\.\$exceptionsMap\$/, - `${JSON.stringify(exceptionsMap, scriptletJsonReplacer)}` + 'self.$hasEntities$', + JSON.stringify(hasEntities) ); writeFile(`${scriptletDir}/declarative/${assetDetails.id}.js`, patchedScriptlet); if ( contentArray.length !== 0 ) { log(`CSS-declarative: ${declaratives.size} distinct filters`); log(`\tCombined into ${hostnamesMap.size} distinct hostnames`); - log(`\tCombined into ${entitiesMap.size} distinct entities`); } - return hostnamesMap.size + entitiesMap.size; + return hostnamesMap.size; } /******************************************************************************/ @@ -878,39 +1147,21 @@ async function processProceduralCosmeticFilters(assetDetails, mapin) { const argsMap = contentArray.map(entry => [ entry[0], - { - a: entry[1].a, - n: entry[1].n, - } + entry[1].a, ]); const hostnamesMap = new Map(); + let hasEntities = false; for ( const [ id, details ] of contentArray ) { - if ( details.y === undefined ) { continue; } - scriptletHostnameToIdMap(details.y, id, hostnamesMap); - } - const argsList = argsMap2List(argsMap, hostnamesMap); - const entitiesMap = new Map(); - for ( const [ hn, details ] of hostnamesMap ) { - if ( hn.endsWith('.*') === false ) { continue; } - hostnamesMap.delete(hn); - entitiesMap.set(hn.slice(0, -2), details); - } - - // Extract exceptions from argsList, simplify argsList entries - const exceptionsMap = new Map(); - for ( let i = 0; i < argsList.length; i++ ) { - const details = argsList[i]; + if ( details.y ) { + scriptletHostnameToIdMap(details.y, id, hostnamesMap); + hasEntities ||= details.y.some(a => a.endsWith('.*')); + } if ( details.n ) { - for ( const hn of details.n ) { - if ( exceptionsMap.has(hn) === false ) { - exceptionsMap.set(hn, []); - } - exceptionsMap.get(hn).push(i); - } + scriptletHostnameToIdMap(details.n.map(a => `~${a}`), id, hostnamesMap); + hasEntities ||= details.n.some(a => a.endsWith('.*')); } - argsList[i] = details.a; } - + const { argsList, argsSeqs } = argsMap2List(argsMap, hostnamesMap); const originalScriptletMap = await loadAllSourceScriptlets(); let patchedScriptlet = originalScriptletMap.get('css-procedural').replace( '$rulesetId$', @@ -921,26 +1172,25 @@ async function processProceduralCosmeticFilters(assetDetails, mapin) { `${JSON.stringify(argsList, scriptletJsonReplacer)}` ); patchedScriptlet = safeReplace(patchedScriptlet, - /\bself\.\$hostnamesMap\$/, - `${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}` + /\bself\.\$argsSeqs\$/, + `${JSON.stringify(argsSeqs, scriptletJsonReplacer)}` ); patchedScriptlet = safeReplace(patchedScriptlet, - /\bself\.\$entitiesMap\$/, - `${JSON.stringify(entitiesMap, scriptletJsonReplacer)}` + /\bself\.\$hostnamesMap\$/, + `${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}` ); patchedScriptlet = safeReplace(patchedScriptlet, - /\bself\.\$exceptionsMap\$/, - `${JSON.stringify(exceptionsMap, scriptletJsonReplacer)}` + 'self.$hasEntities$', + JSON.stringify(hasEntities) ); writeFile(`${scriptletDir}/procedural/${assetDetails.id}.js`, patchedScriptlet); if ( contentArray.length !== 0 ) { log(`Procedural-related distinct filters: ${procedurals.size} distinct combined selectors`); log(`\tCombined into ${hostnamesMap.size} distinct hostnames`); - log(`\tCombined into ${entitiesMap.size} distinct entities`); } - return hostnamesMap.size + entitiesMap.size; + return hostnamesMap.size; } /******************************************************************************/ @@ -952,7 +1202,7 @@ async function processScriptletFilters(assetDetails, mapin) { makeScriptlet.init(); for ( const details of mapin.values() ) { - makeScriptlet.compile(details); + makeScriptlet.compile(assetDetails, details); } const stats = await makeScriptlet.commit( assetDetails.id, @@ -972,16 +1222,28 @@ async function rulesetFromURLs(assetDetails) { log('============================'); log(`Listset for '${assetDetails.id}':`); - if ( assetDetails.text === undefined ) { + if ( assetDetails.text === undefined && assetDetails.urls.length !== 0 ) { const text = await fetchList(assetDetails); - if ( text === '' ) { return; } + if ( text === undefined ) { + process.exit(1); + } assetDetails.text = text; + } else { + assetDetails.text = ''; } - if ( Array.isArray(assetDetails.filters) ) { - assetDetails.text += '\n' + assetDetails.filters.join('\n'); + if ( Array.isArray(assetDetails.filters) && assetDetails.filters.length ) { + const extra = [ + `!#trusted on ${secret}`, + ...assetDetails.filters, + `!#trusted off ${secret}`, + assetDetails.text, + ]; + assetDetails.text = extra.join('\n').trim(); } + if ( assetDetails.text === '' ) { return; } + const extensionPaths = []; for ( const [ fname, details ] of redirectResourcesMap ) { const path = `/web_accessible_resources/${fname}`; @@ -999,8 +1261,12 @@ async function rulesetFromURLs(assetDetails) { const results = await dnrRulesetFromRawLists( [ { name: assetDetails.id, text: assetDetails.text } ], - { env, extensionPaths, secret: assetDetails.secret } + { env, extensionPaths, secret, networkBad } ); + networkBad = results.networkBad; + + // Release memory used by filter list content + assetDetails.text = undefined; const netStats = await processNetworkFilters( assetDetails, @@ -1031,25 +1297,37 @@ async function rulesetFromURLs(assetDetails) { log(rejectedCosmetic.map(line => `\t${line}`).join('\n'), true); } + const genericDetailsForRuleset = {}; if ( Array.isArray(results.network.generichideExclusions) && results.network.generichideExclusions.length !== 0 ) { - genericDetails.set( - assetDetails.id, - results.network.generichideExclusions.filter(hn => hn.endsWith('.*') === false).sort() - ); + genericDetailsForRuleset.unhide = results.network.generichideExclusions + .filter(hn => hn.endsWith('.*') === false) + .sort(); + } + if ( + Array.isArray(results.network.generichideInclusions) && + results.network.generichideInclusions.length !== 0 + ) { + genericDetailsForRuleset.hide = results.network.generichideInclusions + .filter(hn => hn.endsWith('.*') === false) + .sort(); + } + if ( genericDetailsForRuleset.unhide || genericDetailsForRuleset.hide ) { + genericDetails.set(assetDetails.id, genericDetailsForRuleset); } const genericCosmeticStats = await processGenericCosmeticFilters( assetDetails, - results.genericCosmetic, - results.genericCosmeticExceptions + results.genericCosmeticFilters, + results.genericCosmeticExceptions, + declarativeCosmetic ); const genericHighCosmeticStats = await processGenericHighCosmeticFilters( assetDetails, - results.genericHighCosmetic, - results.genericCosmeticExceptions + results.genericCosmeticFilters, + results.genericCosmeticExceptions, ); const specificCosmeticStats = await processCosmeticFilters( assetDetails, @@ -1072,8 +1350,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 +1367,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, }, @@ -1119,183 +1401,33 @@ async function main() { const dayPart = now.getUTCDate(); const hourPart = Math.floor(now.getUTCHours()); const minutePart = Math.floor(now.getUTCMinutes()); - version = `${yearPart}.${monthPart}.${dayPart}.${hourPart * 60 + minutePart}`; + version = `${yearPart}.${monthPart*100+dayPart}.${hourPart*100+minutePart}`; } - log(`Version: ${version}`); + log(`Version: ${version}`, false); - // Get assets.json content - const assets = await fs.readFile( - `./assets.json`, - { encoding: 'utf8' } - ).then(text => + // Get list of rulesets + const rulesets = await fs.readFile('rulesets.json', { + encoding: 'utf8' + }).then(text => JSON.parse(text) ); - // This will be used to sign our inserted `!#trusted on` directives - const secret = createHash('sha256').update(randomBytes(16)).digest('hex').slice(0,16); - log(`Secret: ${secret}`); - - // 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, - 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, - }); + for ( const ruleset of rulesets ) { + if ( ruleset.excludedPlatforms?.includes(platform) ) { continue; } + await rulesetFromURLs(ruleset); } - // Handpicked rulesets from assets.json - const handpicked = [ - 'block-lan', - 'dpollock-0', - 'adguard-spyware-url', - ]; - for ( const id of handpicked ) { - const asset = assets[id]; - if ( asset.content !== 'filters' ) { continue; } - const contentURL = Array.isArray(asset.contentURL) - ? asset.contentURL[0] - : asset.contentURL; - await rulesetFromURLs({ - id: id.toLowerCase(), - name: asset.title, - enabled: false, - urls: [ contentURL ], - homeURL: asset.supportURL, - }); - } - - // Handpicked annoyance rulesets from assets.json - await rulesetFromURLs({ - id: 'annoyances-cookies', - name: 'EasyList/uBO – Cookie Notices', - group: 'annoyances', - enabled: false, - secret, - urls: [ - 'https://ublockorigin.github.io/uAssets/thirdparties/easylist-cookies.txt', - 'https://ublockorigin.github.io/uAssets/filters/annoyances-cookies.txt', - ], - homeURL: 'https://github.com/easylist/easylist#fanboy-lists', - }); - await rulesetFromURLs({ - id: 'annoyances-overlays', - name: 'EasyList/uBO – Overlay Notices', - group: 'annoyances', - enabled: false, - secret, - urls: [ - 'https://ublockorigin.github.io/uAssets/thirdparties/easylist-newsletters.txt', - 'https://ublockorigin.github.io/uAssets/filters/annoyances-others.txt', - ], - homeURL: 'https://github.com/easylist/easylist#fanboy-lists', - }); - await rulesetFromURLs({ - id: 'annoyances-social', - name: 'EasyList – Social Widgets', - group: 'annoyances', - enabled: false, - urls: [ - 'https://ublockorigin.github.io/uAssets/thirdparties/easylist-social.txt', - ], - homeURL: 'https://github.com/easylist/easylist#fanboy-lists', - }); - await rulesetFromURLs({ - id: 'annoyances-widgets', - name: 'EasyList – Chat Widgets', - group: 'annoyances', - enabled: false, - urls: [ - 'https://ublockorigin.github.io/uAssets/thirdparties/easylist-chat.txt', - ], - homeURL: 'https://github.com/easylist/easylist#fanboy-lists', - }); - await rulesetFromURLs({ - id: 'annoyances-others', - name: 'EasyList – Other Annoyances', - group: 'annoyances', - enabled: false, - urls: [ - 'https://ublockorigin.github.io/uAssets/thirdparties/easylist-annoyances.txt' - ], - homeURL: 'https://github.com/easylist/easylist#fanboy-lists', - }); + logProgress(''); - // Handpicked rulesets from abroad - await rulesetFromURLs({ - id: 'stevenblack-hosts', - name: 'Steven Black\'s hosts file', - enabled: false, - urls: [ 'https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts' ], - homeURL: 'https://github.com/StevenBlack/hosts#readme', - }); - - writeFile( - `${rulesetDir}/ruleset-details.json`, + writeFile(`${rulesetDir}/ruleset-details.json`, `${JSON.stringify(rulesetDetails, null, 1)}\n` ); - writeFile( - `${rulesetDir}/scriptlet-details.json`, + writeFile(`${rulesetDir}/scriptlet-details.json`, `${JSON.stringify(scriptletStats, jsonSetMapReplacer, 1)}\n` ); - writeFile( - `${rulesetDir}/generic-details.json`, + writeFile(`${rulesetDir}/generic-details.json`, `${JSON.stringify(genericDetails, jsonSetMapReplacer, 1)}\n` ); @@ -1317,26 +1449,26 @@ 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 || []; const web_accessible_resources = { - resources: Array.from(requiredRedirectResources).map(path => `/${path}`), + resources: Array.from(requiredRedirectResources).map(path => `${path}`), matches: [ '' ], }; - if ( platform === 'chromium' ) { + if ( env.includes('chromium') && env.includes('safari') === false ) { web_accessible_resources.use_dynamic_url = true; } - manifest.web_accessible_resources = [ web_accessible_resources ]; + manifest.web_accessible_resources.push(web_accessible_resources); // Patch manifest version property manifest.version = version; // Commit changes - await fs.writeFile( - `${outputDir}/manifest.json`, + await fs.writeFile(`${outputDir}/manifest.json`, JSON.stringify(manifest, null, 2) + '\n' ); // 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..cf356c5ea2160 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'; /******************************************************************************/ @@ -79,7 +75,7 @@ export function reset() { /******************************************************************************/ -export function compile(details) { +export function compile(assetDetails, details) { if ( details.args[0].endsWith('.js') === false ) { details.args[0] += '.js'; } @@ -89,8 +85,9 @@ export function compile(details) { const scriptletToken = details.args[0]; const resourceEntry = resourceDetails.get(scriptletToken); if ( resourceEntry === undefined ) { return; } + const argsToken = JSON.stringify(details.args.slice(1)); if ( resourceEntry.requiresTrust && details.trustedSource !== true ) { - console.log(`Rejecting ${scriptletToken}: source is not trusted`); + console.log(`Rejecting +js(${scriptletToken},${argsToken.slice(1,-1)}): ${assetDetails.id} is not trusted`); return; } if ( scriptletFiles.has(scriptletToken) === false ) { @@ -100,36 +97,34 @@ export function compile(details) { world: resourceEntry.world, args: new Map(), hostnames: new Map(), - entities: new Map(), exceptions: new Map(), + hasEntities: false, + hasAncestors: false, matches: new Set(), }); } const scriptletDetails = scriptletFiles.get(scriptletToken); - const argsToken = JSON.stringify(details.args.slice(1)); if ( scriptletDetails.args.has(argsToken) === false ) { scriptletDetails.args.set(argsToken, scriptletDetails.args.size); } const iArgs = scriptletDetails.args.get(argsToken); if ( details.matches ) { for ( const hn of details.matches ) { - if ( hn.endsWith('.*') ) { + const isEntity = hn.endsWith('.*') || hn.endsWith('.*>>'); + scriptletDetails.hasEntities ||= isEntity; + const isAncestor = hn.endsWith('>>') + scriptletDetails.hasAncestors ||= isAncestor; + if ( isEntity || isAncestor ) { scriptletDetails.matches.clear(); scriptletDetails.matches.add('*'); - const entity = hn.slice(0, -2); - if ( scriptletDetails.entities.has(entity) === false ) { - scriptletDetails.entities.set(entity, new Set()); - } - scriptletDetails.entities.get(entity).add(iArgs); - } else { - if ( scriptletDetails.matches.has('*') === false ) { - scriptletDetails.matches.add(hn); - } - if ( scriptletDetails.hostnames.has(hn) === false ) { - scriptletDetails.hostnames.set(hn, new Set()); - } - scriptletDetails.hostnames.get(hn).add(iArgs); } + if ( scriptletDetails.matches.has('*') === false ) { + scriptletDetails.matches.add(hn); + } + if ( scriptletDetails.hostnames.has(hn) === false ) { + scriptletDetails.hostnames.set(hn, new Set()); + } + scriptletDetails.hostnames.get(hn).add(iArgs); } } else { scriptletDetails.matches.add('*'); @@ -167,7 +162,6 @@ export async function commit(rulesetId, path, writeFn) { ); content = safeReplace(content, /\$rulesetId\$/, rulesetId, 0); content = safeReplace(content, /\$scriptletName\$/, details.name, 0); - content = safeReplace(content, '$world$', details.world); content = safeReplace(content, 'self.$argsList$', JSON.stringify(Array.from(details.args.keys()).map(a => JSON.parse(a))) @@ -177,15 +171,24 @@ export async function commit(rulesetId, path, writeFn) { JSON.stringify(patchHnMap(details.hostnames)) ); content = safeReplace(content, - 'self.$entitiesMap$', - JSON.stringify(patchHnMap(details.entities)) + 'self.$hasEntities$', + JSON.stringify(details.hasEntities) + ); + content = safeReplace(content, + 'self.$hasAncestors$', + JSON.stringify(details.hasAncestors) ); content = safeReplace(content, 'self.$exceptionsMap$', JSON.stringify(Array.from(details.exceptions)) ); writeFn(`${path}/${rulesetId}.${name}`, content); - scriptletStats.push([ name.slice(0, -3), Array.from(details.matches).sort() ]); + scriptletStats.push([ + name.slice(0, -3), { + hostnames: Array.from(details.matches).sort(), + world: details.world, + } + ]); } return scriptletStats; } diff --git a/platform/mv3/rulesets.json b/platform/mv3/rulesets.json new file mode 100644 index 0000000000000..c2dff26d1c6da --- /dev/null +++ b/platform/mv3/rulesets.json @@ -0,0 +1,614 @@ +[ + { + "id": "ublock-filters", + "name": "uBlock filters – Ads, trackers, and more", + "group": "default", + "enabled": true, + "trusted": true, + "urls": [ + "https://ublockorigin.github.io/uAssets/filters/quick-fixes.min.txt", + "https://ublockorigin.github.io/uAssets/filters/unbreak.min.txt", + "https://ublockorigin.github.io/uAssets/filters/filters.min.txt", + "https://ublockorigin.github.io/uAssets/filters/privacy.min.txt", + "https://ublockorigin.github.io/uAssets/filters/ubol-filters.txt" + ], + "homeURL": "https://github.com/uBlockOrigin/uAssets" + }, + { + "id": "easylist", + "name": "EasyList", + "group": "default", + "enabled": true, + "urls": [ + "https://ublockorigin.github.io/uAssets/thirdparties/easylist.txt" + ], + "homeURL": "https://easylist.to/" + }, + { + "id": "easyprivacy", + "name": "EasyPrivacy", + "group": "default", + "enabled": true, + "urls": [ + "https://ublockorigin.github.io/uAssets/thirdparties/easyprivacy.txt" + ], + "homeURL": "https://easylist.to/" + }, + { + "id": "pgl", + "name": "Peter Lowe – Ads, trackers, and more", + "group": "default", + "enabled": true, + "urls": [ + "https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=1&mimetype=plaintext" + ], + "homeURL": "https://pgl.yoyo.org/adservers/" + }, + { + "id": "ublock-badware", + "name": "uBlock filters – Badware risks", + "group": "malware", + "enabled": true, + "trusted": true, + "urls": [ + "https://ublockorigin.github.io/uAssets/filters/badware.min.txt" + ], + "homeURL": "https://github.com/uBlockOrigin/uAssets" + }, + { + "id": "urlhaus-full", + "name": "Malicious URL Blocklist", + "group": "malware", + "enabled": true, + "excludedPlatforms": [ "safari" ], + "urls": [ + "https://malware-filter.gitlab.io/malware-filter/urlhaus-filter-hosts.txt" + ], + "homeURL": "https://gitlab.com/malware-filter/urlhaus-filter" + }, + { + "id": "adguard-mobile", + "name": "AdGuard – Mobile Ads", + "group": "ads", + "enabled": false, + "tags": "mobile", + "urls": [ + "https://filters.adtidy.org/extension/ublock/filters/11.txt" + ], + "homeURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + { + "id": "block-lan", + "name": "Block Outsider Intrusion into LAN", + "group": "privacy", + "enabled": false, + "urls": [ + "https://ublockorigin.github.io/uAssets/filters/lan-block.txt" + ], + "homeURL": "https://github.com/uBlockOrigin/uAssets" + }, + { + "id": "dpollock-0", + "name": "Dan Pollock’s hosts file", + "enabled": false, + "excludedPlatforms": [ "safari" ], + "urls": [ + "https://someonewhocares.org/hosts/hosts" + ], + "homeURL": "https://someonewhocares.org/hosts/" + }, + { + "id": "adguard-spyware-url", + "name": "AdGuard URL Tracking Protection", + "group": "privacy", + "enabled": false, + "urls": [ + "https://filters.adtidy.org/extension/ublock/filters/17.txt" + ], + "homeURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + { + "id": "annoyances-cookies", + "name": "EasyList/uBO – Cookie Notices", + "group": "annoyances", + "enabled": false, + "urls": [ + "https://ublockorigin.github.io/uAssets/thirdparties/easylist-cookies.txt", + "https://ublockorigin.github.io/uAssets/filters/annoyances-cookies.txt" + ], + "homeURL": "https://github.com/easylist/easylist#fanboy-lists" + }, + { + "id": "annoyances-overlays", + "name": "EasyList/uBO – Overlay Notices", + "group": "annoyances", + "enabled": false, + "urls": [ + "https://ublockorigin.github.io/uAssets/thirdparties/easylist-newsletters.txt", + "https://ublockorigin.github.io/uAssets/filters/annoyances-others.txt" + ], + "homeURL": "https://github.com/easylist/easylist#fanboy-lists" + }, + { + "id": "annoyances-social", + "name": "EasyList – Social Widgets", + "group": "annoyances", + "enabled": false, + "urls": [ + "https://ublockorigin.github.io/uAssets/thirdparties/easylist-social.txt" + ], + "homeURL": "https://github.com/easylist/easylist#fanboy-lists" + }, + { + "id": "annoyances-widgets", + "name": "EasyList – Chat Widgets", + "group": "annoyances", + "enabled": false, + "urls": [ + "https://ublockorigin.github.io/uAssets/thirdparties/easylist-chat.txt" + ], + "homeURL": "https://github.com/easylist/easylist#fanboy-lists" + }, + { + "id": "annoyances-others", + "name": "EasyList – Other Annoyances", + "group": "annoyances", + "enabled": false, + "urls": [ + "https://ublockorigin.github.io/uAssets/thirdparties/easylist-annoyances.txt" + ], + "homeURL": "https://github.com/easylist/easylist#fanboy-lists" + }, + { + "id": "stevenblack-hosts", + "name": "Steven Black’s Unified Hosts (adware + malware)", + "enabled": false, + "excludedPlatforms": [ "safari" ], + "urls": [ + "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" + ], + "homeURL": "https://github.com/StevenBlack/hosts#readme" + }, + { + "id": "ubol-tests", + "name": "uBO Lite Test Filters", + "enabled": false, + "trusted": true, + "urls": [ + "https://ublockorigin.github.io/uBOL-home/tests/test-filters.txt" + ], + "homeURL": "https://ublockorigin.github.io/uBOL-home/tests/test-filters.html" + }, + { + "id": "alb-0", + "group": "regions", + "lang": "sq", + "name": "🇦🇱al 🇽🇰xk: Adblock List for Albania", + "tags": "ads albania shqipja", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/AnXh3L0/blocklist/master/albanian-easylist-addition/Albania.txt" + ], + "homeURL": "https://github.com/AnXh3L0/blocklist" + }, + { + "id": "bgr-0", + "group": "regions", + "lang": "bg mk", + "name": "🇧🇬bg: Bulgarian Adblock list", + "tags": "ads bulgarian България macedonian Македонија", + "enabled": false, + "urls": [ + "https://stanev.org/abp/adblock_bg.txt" + ], + "homeURL": "https://stanev.org/abp/" + }, + { + "id": "chn-0", + "group": "regions", + "lang": "ug zh", + "name": "🇨🇳cn 🇹🇼tw: AdGuard Chinese (中文)", + "tags": "ads chinese 中文", + "enabled": false, + "urls": [ + "https://filters.adtidy.org/extension/ublock/filters/224.txt" + ], + "homeURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + { + "id": "cze-0", + "group": "regions", + "lang": "cs sk", + "name": "🇨🇿cz 🇸🇰sk: EasyList Czech and Slovak", + "tags": "ads czech česká slovak slovenská", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/tomasko126/easylistczechandslovak/master/filters.txt" + ], + "homeURL": "https://github.com/tomasko126/easylistczechandslovak" + }, + { + "id": "deu-0", + "group": "regions", + "lang": "de dsb hsb lb rm", + "name": "🇩🇪de 🇨🇭ch 🇦🇹at: EasyList Germany", + "tags": "ads german deutschland luxembourgish lëtzebuerg romansh", + "enabled": false, + "urls": [ + "https://easylist.to/easylistgermany/easylistgermany.txt" + ], + "homeURL": "https://forums.lanik.us/viewforum.php?f=90" + }, + { + "id": "est-0", + "group": "regions", + "lang": "et", + "name": "🇪🇪ee: Eesti saitidele kohandatud filter", + "enabled": false, + "urls": [ + "https://ubol-et.adblock.ee/list.txt" + ], + "homeURL": "https://github.com/sander85/uBOL-et" + }, + { + "id": "fin-0", + "group": "regions", + "lang": "fi", + "name": "🇫🇮fi: Adblock List for Finland", + "tags": "ads finnish", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/finnish-easylist-addition/finnish-easylist-addition/gh-pages/Finland_adb.txt" + ], + "homeURL": "https://github.com/finnish-easylist-addition/finnish-easylist-addition" + }, + { + "id": "fra-0", + "group": "regions", + "lang": "ar br ff fr lb oc son", + "name": "🇫🇷fr 🇨🇦ca: AdGuard Français", + "tags": "ads french", + "enabled": false, + "urls": [ + "https://filters.adtidy.org/extension/ublock/filters/16.txt" + ], + "homeURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + { + "id": "grc-0", + "group": "regions", + "lang": "el", + "name": "🇬🇷gr 🇨🇾cy: Greek AdBlock Filter", + "tags": "ads greek", + "enabled": false, + "urls": [ + "https://www.void.gr/kargig/void-gr-filters.txt" + ], + "homeURL": "https://github.com/kargig/greek-adblockplus-filter" + }, + { + "id": "hrv-0", + "group": "regions", + "lang": "bs hr sr", + "name": "🇭🇷hr 🇷🇸rs: Dandelion Sprout's Serbo-Croatian filters", + "tags": "ads croatian serbian bosnian", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/DandelionSprout/adfilt/master/SerboCroatianList.txt" + ], + "homeURL": "https://github.com/DandelionSprout/adfilt#readme" + }, + { + "id": "hun-0", + "group": "regions", + "lang": "hu", + "name": "🇭🇺hu: hufilter", + "tags": "ads hungarian", + "enabled": false, + "urls": [ + "https://cdn.jsdelivr.net/gh/hufilter/hufilter@gh-pages/hufilter-ublock.txt" + ], + "homeURL": "https://github.com/hufilter/hufilter" + }, + { + "id": "idn-0", + "group": "regions", + "lang": "id ms", + "name": "🇮🇩id 🇲🇾my: ABPindo", + "tags": "ads indonesian malay", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/ABPindo/indonesianadblockrules/master/subscriptions/abpindo.txt" + ], + "homeURL": "https://github.com/ABPindo/indonesianadblockrules" + }, + { + "id": "ind-0", + "group": "regions", + "lang": "as bn gu hi kn ml mr ne pa si ta te", + "name": "🇮🇳in 🇱🇰lk 🇳🇵np: IndianList", + "tags": "ads assamese bengali gujarati hindi kannada malayalam marathi nepali punjabi sinhala tamil telugu", + "enabled": false, + "urls": [ + "https://easylist-downloads.adblockplus.org/indianlist.txt" + ], + "homeURL": "https://github.com/mediumkreation/IndianList" + }, + { + "id": "irn-0", + "group": "regions", + "lang": "fa ps tg", + "name": "🇮🇷ir: PersianBlocker", + "tags": "ads af ir persian pashto tajik tj", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/MasterKia/PersianBlocker/main/PersianBlocker.txt" + ], + "homeURL": "https://github.com/MasterKia/PersianBlocker" + }, + { + "id": "isl-0", + "group": "regions", + "lang": "is", + "name": "🇮🇸is: Icelandic ABP List", + "tags": "ads icelandic", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/brave/adblock-lists/master/custom/is.txt" + ], + "homeURL": "https://github.com/brave/adblock-lists/issues" + }, + { + "id": "isr-0", + "group": "regions", + "lang": "he", + "name": "🇮🇱il: EasyList Hebrew", + "tags": "ads hebrew", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/easylist/EasyListHebrew/master/EasyListHebrew.txt" + ], + "homeURL": "https://github.com/easylist/EasyListHebrew" + }, + { + "id": "ita-0", + "group": "regions", + "lang": "it lij", + "name": "🇮🇹it: EasyList Italy", + "tags": "ads italian", + "enabled": false, + "urls": [ + "https://easylist-downloads.adblockplus.org/easylistitaly.txt" + ], + "homeURL": "https://forums.lanik.us/viewforum.php?f=96" + }, + { + "id": "jpn-1", + "group": "regions", + "lang": "ja", + "name": "🇯🇵jp: AdGuard Japanese", + "tags": "ads japanese 日本語", + "enabled": false, + "urls": [ + "https://filters.adtidy.org/extension/ublock/filters/7.txt" + ], + "homeURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + { + "id": "kor-1", + "group": "regions", + "lang": "ko", + "name": "🇰🇷kr: List-KR", + "tags": "ads korean 한국어", + "enabled": false, + "urls": [ + "https://cdn.jsdelivr.net/gh/List-KR/List-KR@latest/filter-uBlockOrigin.txt" + ], + "homeURL": "https://github.com/List-KR/List-KR#readme" + }, + { + "id": "ltu-0", + "group": "regions", + "lang": "lt", + "name": "🇱🇹lt: EasyList Lithuania", + "tags": "ads lithuanian", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/EasyList-Lithuania/easylist_lithuania/master/easylistlithuania.txt" + ], + "homeURL": "https://github.com/EasyList-Lithuania/easylist_lithuania" + }, + { + "id": "lva-0", + "group": "regions", + "lang": "lv", + "name": "🇱🇻lv: Latvian List", + "tags": "ads latvian", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/Latvian-List/adblock-latvian/master/lists/latvian-list.txt" + ], + "homeURL": "https://github.com/Latvian-List/adblock-latvian" + }, + { + "id": "mkd-0", + "group": "regions", + "lang": "mk", + "name": "🇲🇰mk: Macedonian adBlock Filters", + "tags": "ads macedonian", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/DeepSpaceHarbor/Macedonian-adBlock-Filters/master/Filters" + ], + "homeURL": "https://github.com/DeepSpaceHarbor/Macedonian-adBlock-Filters" + }, + { + "id": "nld-0", + "group": "regions", + "lang": "af fy nl", + "name": "🇳🇱nl 🇧🇪be: AdGuard Dutch", + "tags": "ads afrikaans be belgië frisian dutch flemish nederlands netherlands nl sr suriname za", + "enabled": false, + "urls": [ + "https://filters.adtidy.org/extension/ublock/filters/8.txt" + ], + "homeURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + { + "id": "nor-0", + "group": "regions", + "lang": "nb nn no da is", + "name": "🇳🇴no 🇩🇰dk 🇮🇸is: Dandelion Sprouts nordiske filtre", + "tags": "ads norwegian danish icelandic", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/DandelionSprout/adfilt/master/NorwegianList.txt" + ], + "homeURL": "https://github.com/DandelionSprout/adfilt" + }, + { + "id": "pol-0", + "group": "regions", + "lang": "szl pl _", + "name": "🇵🇱pl: Oficjalne Polskie Filtry do uBlocka Origin", + "tags": "ads polish polski", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/MajkiIT/polish-ads-filter/master/polish-adblock-filters/adblock.txt" + ], + "homeURL": "https://github.com/MajkiIT/polish-ads-filter" + }, + { + "id": "rou-1", + "group": "regions", + "lang": "ro", + "name": "🇷🇴ro 🇲🇩md: Romanian Ad (ROad) Block List Light", + "tags": "ads romanian română moldavian moldovenească молдовеняскэ", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/tcptomato/ROad-Block/master/road-block-filters-light.txt" + ], + "homeURL": "https://github.com/tcptomato/ROad-Block" + }, + { + "id": "rus-0", + "group": "regions", + "parent": "🇷🇺ru 🇺🇦ua 🇺🇿uz 🇰🇿kz: RU AdList", + "lang": "be kk tt ru uz", + "name": "🇷🇺ru 🇺🇦ua 🇺🇿uz 🇰🇿kz: RU AdList", + "tags": "ads belarusian беларуская kazakh tatar russian русский ukrainian українська uzbek uk", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/easylist/ruadlist/master/RuAdList-uBO.txt" + ], + "homeURL": "https://forums.lanik.us/viewforum.php?f=102" + }, + { + "id": "rus-1", + "group": "regions", + "parent": "🇷🇺ru 🇺🇦ua 🇺🇿uz 🇰🇿kz: RU AdList", + "name": "🇷🇺ru 🇺🇦ua 🇺🇿uz 🇰🇿kz: RU AdList: Counters", + "tags": "ads belarusian беларуская kazakh tatar russian русский ukrainian українська uzbek be kk tt ru uk uz", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/easylist/ruadlist/master/cntblock.txt" + ], + "homeURL": "https://forums.lanik.us/viewforum.php?f=102" + }, + { + "id": "spa-0", + "group": "regions", + "lang": "an ast ca cak es eu gl gn trs quz", + "name": "🇪🇸es 🇦🇷ar 🇲🇽mx 🇨🇴co: EasyList Spanish", + "tags": "ads aragonese basque catalan spanish español galician guarani", + "enabled": false, + "urls": [ + "https://easylist-downloads.adblockplus.org/easylistspanish.txt" + ], + "homeURL": "https://forums.lanik.us/viewforum.php?f=103" + }, + { + "id": "spa-1", + "group": "regions", + "lang": "an ast ca cak es eu gl gn trs pt quz", + "name": "🇪🇸es 🇦🇷ar 🇧🇷br 🇵🇹pt: AdGuard Spanish/Portuguese", + "tags": "ads aragonese basque catalan spanish español galician guarani portuguese português", + "enabled": false, + "urls": [ + "https://filters.adtidy.org/extension/ublock/filters/9.txt" + ], + "homeURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + { + "id": "svn-0", + "group": "regions", + "lang": "sl", + "name": "🇸🇮si: Slovenian List", + "tags": "ads slovenian slovenski", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/betterwebleon/slovenian-list/master/filters.txt" + ], + "homeURL": "https://github.com/betterwebleon/slovenian-list" + }, + { + "id": "swe-1", + "group": "regions", + "lang": "sv", + "name": "🇸🇪se: Frellwit's Swedish Filter", + "tags": "ads swedish svenska", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/lassekongo83/Frellwits-filter-lists/master/Frellwits-Swedish-Filter.txt" + ], + "homeURL": "https://github.com/lassekongo83/Frellwits-filter-lists" + }, + { + "id": "tha-0", + "group": "regions", + "lang": "th", + "name": "🇹🇭th: EasyList Thailand", + "tags": "ads thai ไทย", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/easylist-thailand/easylist-thailand/master/subscription/easylist-thailand.txt" + ], + "homeURL": "https://github.com/easylist-thailand/easylist-thailand" + }, + { + "id": "tur-0", + "group": "regions", + "lang": "tr", + "name": "🇹🇷tr: AdGuard Turkish", + "tags": "ads turkish türkçe", + "enabled": false, + "urls": [ + "https://filters.adtidy.org/extension/ublock/filters/13.txt" + ], + "homeURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + { + "id": "ukr-0", + "group": "regions", + "lang": "uk", + "name": "🇺🇦ua: AdGuard Ukrainian", + "tags": "ads ukraine україна", + "enabled": false, + "urls": [ + "https://filters.adtidy.org/extension/ublock/filters/23.txt" + ], + "homeURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters" + }, + { + "id": "vie-1", + "group": "regions", + "lang": "vi", + "name": "🇻🇳vn: ABPVN List", + "tags": "ads vietnamese việt", + "enabled": false, + "urls": [ + "https://raw.githubusercontent.com/abpvn/abpvn/master/filter/abpvn_ublock.txt" + ], + "homeURL": "https://abpvn.com/" + } +] diff --git a/platform/mv3/safari/ext-compat.js b/platform/mv3/safari/ext-compat.js new file mode 100644 index 0000000000000..772f17c81eefe --- /dev/null +++ b/platform/mv3/safari/ext-compat.js @@ -0,0 +1,183 @@ +/******************************************************************************* + + uBlock Origin Lite - a comprehensive, MV3-compliant content blocker + Copyright (C) 2022-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + + +export const webext = self.browser; + +/******************************************************************************/ + +// https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/declarativeNetRequest/ + +const nativeDNR = webext.declarativeNetRequest; + +const isSupportedRule = r => { + if ( r.action.responseHeaders ) { return false; } + const { condition } = r; + if ( condition.tabIds !== undefined ) { return false; } + if ( condition.resourceTypes?.includes('object') ) { + if ( condition.resourceTypes.length === 1 ) { return false; } + const i = condition.resourceTypes.indexOf('object'); + condition.resourceTypes.splice(i, 1); + } + if ( condition.excludedResourceTypes?.includes('object') ) { + const i = condition.excludedResourceTypes.indexOf('object'); + condition.excludedResourceTypes.splice(i, 1); + if ( condition.excludedResourceTypes.length === 0 ) { + delete condition.excludedResourceTypes; + } + } + return true; +}; + +const prepareUpdateRules = optionsBefore => { + const { addRules, removeRuleIds } = optionsBefore; + const addRulesAfter = addRules?.filter(isSupportedRule); + if ( Boolean(addRulesAfter?.length || removeRuleIds?.length) === false ) { return; } + addRulesAfter?.forEach(r => { + if ( r.action?.redirect?.regexSubstitution ) { + if ( r.condition?.requestDomains ) { + r.condition.domains = r.condition.requestDomains; + delete r.condition.requestDomains; + return; + } + } + if ( r.condition?.initiatorDomains ) { + r.condition.domains = r.condition.initiatorDomains; + delete r.condition.initiatorDomains; + } + if ( r.condition?.excludedInitiatorDomains ) { + r.condition.excludedDomains = r.condition.excludedInitiatorDomains; + delete r.condition.excludedInitiatorDomains; + } + }); + const optionsAfter = {}; + if ( addRulesAfter?.length ) { optionsAfter.addRules = addRulesAfter; } + if ( removeRuleIds?.length ) { optionsAfter.removeRuleIds = removeRuleIds; } + return optionsAfter; +}; + +const ruleCompare = (a, b) => a.id - b.id; + +const isSameRules = (a, b) => { + a.sort(ruleCompare); + b.sort(ruleCompare); + return JSON.stringify(a) === JSON.stringify(b); +}; + +/******************************************************************************/ + +export function normalizeDNRRules(rules, ruleIds) { + if ( Array.isArray(rules) === false ) { return rules; } + const selectedRules = Array.isArray(ruleIds) + ? rules.filter(rule => ruleIds.includes(rule.id)) + : rules; + selectedRules.forEach(rule => { + const { condition } = rule; + if ( Array.isArray(condition.domains) ) { + condition.initiatorDomains = condition.domains; + delete condition.domains; + } + if ( Array.isArray(condition.excludedDomains) ) { + condition.excludedInitiatorDomains = condition.excludedDomains; + delete condition.excludedDomains; + } + }); + return selectedRules; +} + +/******************************************************************************/ + +export const dnr = { + DYNAMIC_RULESET_ID: '_dynamic', + MAX_NUMBER_OF_ENABLED_STATIC_RULESETS: nativeDNR.MAX_NUMBER_OF_ENABLED_STATIC_RULESETS, + MAX_NUMBER_OF_REGEX_RULES: nativeDNR.MAX_NUMBER_OF_DYNAMIC_AND_SESSION_RULES, + async getAvailableStaticRuleCount() { + return 150000; + }, + getDynamicRules({ ruleIds } = {}) { + return new Promise(resolve => { + nativeDNR.getDynamicRules(rules => { + if ( Array.isArray(rules) === false ) { return resolve([]); } + return resolve(normalizeDNRRules(rules, ruleIds)); + }); + }); + }, + getEnabledRulesets(...args) { + return nativeDNR.getEnabledRulesets(...args); + }, + getMatchedRules(...args) { + return nativeDNR.getMatchedRules(...args); + }, + getSessionRules({ ruleIds } = {}) { + return new Promise(resolve => { + nativeDNR.getSessionRules(rules => { + if ( Array.isArray(rules) === false ) { return resolve([]); } + return resolve(normalizeDNRRules(rules, ruleIds)); + }); + }); + }, + isRegexSupported(...args) { + return nativeDNR.isRegexSupported(...args); + }, + async updateDynamicRules(optionsBefore) { + const optionsAfter = prepareUpdateRules(optionsBefore); + if ( optionsAfter === undefined ) { return; } + return nativeDNR.updateDynamicRules(optionsAfter); + }, + updateEnabledRulesets(...args) { + return nativeDNR.updateEnabledRulesets(...args); + }, + async updateSessionRules(optionsBefore) { + const optionsAfter = prepareUpdateRules(optionsBefore); + if ( optionsAfter === undefined ) { return; } + return nativeDNR.updateSessionRules(optionsAfter); + }, + async setAllowAllRules(id, allowed, notAllowed, reverse, priority) { + const beforeRules = await this.getDynamicRules({ ruleIds: [ id+0 ] }); + const addRules = []; + if ( reverse || allowed.length || notAllowed.length ) { + const rule0 = { + id: id+0, + action: { type: 'allow' }, + condition: { urlFilter: '*' }, + priority, + }; + if ( allowed.length ) { + rule0.condition.domains = allowed; + } else if ( notAllowed.length ) { + rule0.condition.excludedDomains = notAllowed; + } + addRules.push(rule0); + } + if ( isSameRules(addRules, beforeRules) ) { return false; } + return this.updateDynamicRules({ + addRules, + removeRuleIds: beforeRules.map(r => r.id), + }).then(( ) => + true + ).catch(( ) => + false + ); + }, + setExtensionActionOptions(...args) { + return nativeDNR.setExtensionActionOptions(...args); + }, +}; diff --git a/platform/mv3/safari/manifest.json b/platform/mv3/safari/manifest.json new file mode 100644 index 0000000000000..667e2809058fb --- /dev/null +++ b/platform/mv3/safari/manifest.json @@ -0,0 +1,89 @@ +{ + "action": { + "default_icon": "/img/icon_64.png", + "default_popup": "popup.html" + }, + "author": "Raymond Hill", + "background": { + "scripts": [ "/js/background.js" ], + "type": "module", + "persistent": false + }, + "browser_specific_settings": { + "safari": { + "strict_min_version": "18.4" + } + }, + "commands": { + "enter-zapper-mode": { + "description": "__MSG_zapperTipEnter__" + }, + "enter-picker-mode": { + "description": "__MSG_pickerTipEnter__" + } + }, + "declarative_net_request": { + "rule_resources": [ + ] + }, + "default_locale": "en", + "description": "__MSG_extShortDesc__", + "icons": { + "16": "/img/icon_16.png", + "32": "/img/icon_32.png", + "64": "/img/icon_64.png", + "128": "/img/icon_128.png", + "512": "/img/icon_512.png" + }, + "manifest_version": 3, + "name": "__MSG_extName__", + "options_ui": { + "page": "dashboard.html" + }, + "host_permissions": [ + "" + ], + "permissions": [ + "activeTab", + "declarativeNetRequest", + "declarativeNetRequestWithHostAccess", + "scripting", + "storage" + ], + "short_name": "uBO Lite", + "version": "1.0", + "web_accessible_resources": [ + { + "resources": [ + "strictblock.html" + ], + "matches": [ + "" + ] + }, + { + "resources": [ + "zapper-ui.html" + ], + "matches": [ + "" + ] + }, + { + "resources": [ + "picker-ui.html" + ], + "matches": [ + "" + ] + }, + { + "resources": [ + "unpicker-ui.html" + ], + "matches": [ + "" + ] + } + ] +} diff --git a/platform/mv3/safari/patch-extension.js b/platform/mv3/safari/patch-extension.js new file mode 100644 index 0000000000000..142d48033936b --- /dev/null +++ b/platform/mv3/safari/patch-extension.js @@ -0,0 +1,107 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +import fs from 'fs/promises'; +import process from 'process'; + +/******************************************************************************/ + +const commandLineArgs = (( ) => { + const args = Object.create(null); + let name, value; + for ( const arg of process.argv.slice(2) ) { + const pos = arg.indexOf('='); + if ( pos === -1 ) { + name = arg; + value = ''; + } else { + name = arg.slice(0, pos); + value = arg.slice(pos+1); + } + args[name] = value; + } + return args; +})(); + +/******************************************************************************/ + +// Apple store rejects when description (extShortDesc) is longer than 112 +// characters. + +async function fixLongDescription(path) { + let text = await fs.readFile(path, { encoding: 'utf8' }); + const messages = JSON.parse(text); + let message = messages.extShortDesc.message; + if ( message.length <= 112 ) { return; } + const pos = message.indexOf('.'); + if ( pos !== -1 ) { + message = message.slice(0, pos+1); + } + if ( message.length >= 112 ) { + message = `${message.slice(0, 111)}…`; + } + messages.extShortDesc.message = message; + text = JSON.stringify(messages, null, 2); + await fs.writeFile(path, text); +} + +async function fixLongDescriptions() { + const promises = []; + const packageDir = commandLineArgs.packageDir; + const entries = await fs.readdir(`${packageDir}/_locales/`, { withFileTypes: true }); + for ( const entry of entries ) { + if ( entry.isDirectory() === false ) { continue; } + promises.push(fixLongDescription(`${packageDir}/_locales/${entry.name}/messages.json`)); + } + return Promise.all(promises); +} + +/******************************************************************************/ + +// Apple store rejects when version has four components. + +async function fixManifest() { + const packageDir = commandLineArgs.packageDir; + const path = `${packageDir}/manifest.json`; + let text = await fs.readFile(path, { encoding: 'utf8' }); + const manifest = JSON.parse(text); + const match = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/.exec(manifest.version); + if ( match === null ) { return; } + const month = parseInt(match[2], 10); + const dayofmonth = parseInt(match[3], 10); + const monthday /* sort of */ = month * 100 + dayofmonth; + manifest.version = `${match[1]}.${monthday}.${match[4]}`; + text = JSON.stringify(manifest, null, 2); + await fs.writeFile(path, text); +} + +/******************************************************************************/ + +async function main() { + await Promise.all([ + fixLongDescriptions(), + fixManifest(), + ]); +} + +main(); + +/******************************************************************************/ diff --git a/platform/mv3/safari/patch-ruleset.js b/platform/mv3/safari/patch-ruleset.js new file mode 100644 index 0000000000000..27cc6f1defb05 --- /dev/null +++ b/platform/mv3/safari/patch-ruleset.js @@ -0,0 +1,51 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2025-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +function patchRuleWithRequestDomains(rule, out) { + const requestDomains = rule.condition.requestDomains; + delete rule.condition.requestDomains; + for ( const domain of requestDomains ) { + const newRule = structuredClone(rule); + newRule.condition.urlFilter = `||${domain}^`; + out.push(newRule); + } +} + +export function patchRuleset(ruleset) { + const out = []; + for ( const rule of ruleset ) { + const condition = rule.condition; + if ( rule.action.type === 'modifyHeaders' ) { continue; } + if ( Array.isArray(rule.condition.responseHeaders) ) { continue; } + if ( Array.isArray(condition.requestMethods) ) { continue; } + if ( Array.isArray(condition.excludedRequestMethods) ) { continue; } + if ( Array.isArray(condition.initiatorDomains) ) { + condition.domains = condition.initiatorDomains; + delete condition.initiatorDomains; + } + if ( Array.isArray(condition.excludedInitiatorDomains) ) { + condition.excludedDomains = condition.excludedInitiatorDomains; + delete condition.excludedInitiatorDomains; + } + out.push(rule); + } + return out; +} diff --git a/platform/mv3/safe-replace.js b/platform/mv3/safe-replace.js index b56e5e5af5781..6f417b20b733c 100644 --- a/platform/mv3/safe-replace.js +++ b/platform/mv3/safe-replace.js @@ -19,10 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - export function safeReplace(text, pattern, replacement, count = 1) { const rePattern = typeof pattern === 'string' ? new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) diff --git a/platform/mv3/salvage-ruleids.mjs b/platform/mv3/salvage-ruleids.mjs index f11d986e76855..c272597b9b420 100644 --- a/platform/mv3/salvage-ruleids.mjs +++ b/platform/mv3/salvage-ruleids.mjs @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - /******************************************************************************/ import fs from 'fs/promises'; @@ -64,15 +62,16 @@ async function main() { ]; const writePromises = []; for ( const folder of folders ) { - const afterFiles = await fs.readdir(`${afterDir}/rulesets/${folder}`); + const afterFiles = await fs.readdir(`${afterDir}/rulesets/${folder}`).catch(( ) => { }); + if ( afterFiles === undefined ) { continue; } for ( const file of afterFiles ) { let raw = await fs.readFile(`${beforeDir}/rulesets/${folder}/${file}`, 'utf-8').catch(( ) => ''); let beforeRules; - try { beforeRules = JSON.parse(raw); } catch(_) { } + try { beforeRules = JSON.parse(raw); } catch { } if ( Array.isArray(beforeRules) === false ) { continue; } raw = await fs.readFile(`${afterDir}/rulesets/${folder}/${file}`, 'utf-8').catch(( ) => ''); let afterRules; - try { afterRules = JSON.parse(raw); } catch(_) { } + try { afterRules = JSON.parse(raw); } catch { } if ( Array.isArray(afterRules) === false ) { continue; } const beforeMap = new Map(beforeRules.map(a => { const id = a.id; diff --git a/platform/mv3/scriptlets/css-declarative.template.js b/platform/mv3/scriptlets/css-declarative.template.js index c1f480fab6eb9..f7d467600af7f 100644 --- a/platform/mv3/scriptlets/css-declarative.template.js +++ b/platform/mv3/scriptlets/css-declarative.template.js @@ -19,14 +19,8 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - // ruleset: $rulesetId$ -/******************************************************************************/ - // Important! // Isolate from global scope (function uBOL_cssDeclarativeImport() { @@ -34,15 +28,12 @@ /******************************************************************************/ const argsList = self.$argsList$; - +const argsSeqs = self.$argsSeqs$; const hostnamesMap = new Map(self.$hostnamesMap$); - -const entitiesMap = new Map(self.$entitiesMap$); - -const exceptionsMap = new Map(self.$exceptionsMap$); +const hasEntities = self.$hasEntities$; self.declarativeImports = self.declarativeImports || []; -self.declarativeImports.push({ argsList, hostnamesMap, entitiesMap, exceptionsMap }); +self.declarativeImports.push({ argsList, argsSeqs, hostnamesMap, hasEntities }); /******************************************************************************/ diff --git a/platform/mv3/scriptlets/css-generic.template.js b/platform/mv3/scriptlets/css-generic.template.js index a1f1d6c047604..a353d58544016 100644 --- a/platform/mv3/scriptlets/css-generic.template.js +++ b/platform/mv3/scriptlets/css-generic.template.js @@ -19,11 +19,7 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - -/******************************************************************************/ +// $rulesetId$ // Important! // Isolate from global scope @@ -31,28 +27,58 @@ /******************************************************************************/ -// $rulesetId$ - -const toImport = self.$genericSelectorMap$; - -const genericSelectorMap = self.genericSelectorMap || new Map(); - -if ( genericSelectorMap.size === 0 ) { - self.genericSelectorMap = new Map(toImport); - return; +const genericSelectorMap = self.$genericSelectorMap$; +const genericExceptionSieve = self.$genericExceptionSieve$; +const genericExceptionMap = self.$genericExceptionMap$; + +if ( genericSelectorMap ) { + const map = self.genericSelectorMap = + self.genericSelectorMap || new Map(); + if ( map.size !== 0 ) { + for ( const entry of genericSelectorMap ) { + const before = map.get(entry[0]); + if ( before === undefined ) { + map.set(entry[0], entry[1]); + } else { + map.set(entry[0], `${before},\n${entry[1]}`); + } + } + } else { + self.genericSelectorMap = new Map(genericSelectorMap); + } + genericSelectorMap.length = 0; } -for ( const toImportEntry of toImport ) { - const existing = genericSelectorMap.get(toImportEntry[0]); - genericSelectorMap.set( - toImportEntry[0], - existing === undefined - ? toImportEntry[1] - : `${existing},${toImportEntry[1]}` - ); +if ( genericExceptionSieve ) { + const hashes = self.genericExceptionSieve = + self.genericExceptionSieve || new Set(); + if ( hashes.size !== 0 ) { + for ( const hash of genericExceptionSieve ) { + hashes.add(hash); + } + } else { + self.genericExceptionSieve = new Set(genericExceptionSieve); + } + genericExceptionSieve.length = 0; } -self.genericSelectorMap = genericSelectorMap; +if ( genericExceptionMap ) { + const map = self.genericExceptionMap = + self.genericExceptionMap || new Map(); + if ( map.size !== 0 ) { + for ( const entry of genericExceptionMap ) { + const before = map.get(entry[0]); + if ( before === undefined ) { + map.set(entry[0], entry[1]); + } else { + map.set(entry[0], `${before}\n${entry[1]}`); + } + } + } else { + self.genericExceptionMap = new Map(genericExceptionMap); + } + genericExceptionMap.length = 0; +} /******************************************************************************/ diff --git a/platform/mv3/scriptlets/css-procedural.template.js b/platform/mv3/scriptlets/css-procedural.template.js index 61c95e60695d4..1928abdd488cc 100644 --- a/platform/mv3/scriptlets/css-procedural.template.js +++ b/platform/mv3/scriptlets/css-procedural.template.js @@ -19,14 +19,8 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - // ruleset: $rulesetId$ -/******************************************************************************/ - // Important! // Isolate from global scope (function uBOL_cssProceduralImport() { @@ -34,15 +28,12 @@ /******************************************************************************/ const argsList = self.$argsList$; - +const argsSeqs = self.$argsSeqs$; const hostnamesMap = new Map(self.$hostnamesMap$); - -const entitiesMap = new Map(self.$entitiesMap$); - -const exceptionsMap = new Map(self.$exceptionsMap$); +const hasEntities = self.$hasEntities$; self.proceduralImports = self.proceduralImports || []; -self.proceduralImports.push({ argsList, hostnamesMap, entitiesMap, exceptionsMap }); +self.proceduralImports.push({ argsList, argsSeqs, hostnamesMap, hasEntities }); /******************************************************************************/ diff --git a/platform/mv3/scriptlets/css-specific.template.js b/platform/mv3/scriptlets/css-specific.template.js index 68589312fffa5..f4c93cdf0f752 100644 --- a/platform/mv3/scriptlets/css-specific.template.js +++ b/platform/mv3/scriptlets/css-specific.template.js @@ -19,14 +19,8 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - // ruleset: $rulesetId$ -/******************************************************************************/ - // Important! // Isolate from global scope (function uBOL_cssSpecificImports() { @@ -34,15 +28,12 @@ /******************************************************************************/ const argsList = self.$argsList$; - +const argsSeqs = self.$argsSeqs$; const hostnamesMap = new Map(self.$hostnamesMap$); - -const entitiesMap = new Map(self.$entitiesMap$); - -const exceptionsMap = new Map(self.$exceptionsMap$); +const hasEntities = self.$hasEntities$; self.specificImports = self.specificImports || []; -self.specificImports.push({ argsList, hostnamesMap, entitiesMap, exceptionsMap }); +self.specificImports.push({ argsList, argsSeqs, hostnamesMap, hasEntities }); /******************************************************************************/ diff --git a/platform/mv3/scriptlets/scriptlet.template.js b/platform/mv3/scriptlets/scriptlet.template.js index f5a47483b5ec8..fb5ace81870f0 100644 --- a/platform/mv3/scriptlets/scriptlet.template.js +++ b/platform/mv3/scriptlets/scriptlet.template.js @@ -20,149 +20,92 @@ */ -/* jshint esversion:11 */ -/* global cloneInto */ - -'use strict'; - // ruleset: $rulesetId$ -/******************************************************************************/ - // Important! // Isolate from global scope // Start of local scope -(( ) => { +(function uBOL_$scriptletName$() { /******************************************************************************/ -// Start of code to inject -const uBOL_$scriptletName$ = function() { +function $scriptletName$(){} -const scriptletGlobals = {}; // jshint ignore: line +/******************************************************************************/ +const scriptletGlobals = {}; // eslint-disable-line const argsList = self.$argsList$; - const hostnamesMap = new Map(self.$hostnamesMap$); - -const entitiesMap = new Map(self.$entitiesMap$); - const exceptionsMap = new Map(self.$exceptionsMap$); +const hasEntities = self.$hasEntities$; +const hasAncestors = self.$hasAncestors$; -/******************************************************************************/ - -function $scriptletName$(){} - -/******************************************************************************/ - -const hnParts = []; -try { hnParts.push(...document.location.hostname.split('.')); } -catch(ex) { } -const hnpartslen = hnParts.length; -if ( hnpartslen === 0 ) { return; } - -const todoIndices = new Set(); -const tonotdoIndices = []; - -// Exceptions -if ( exceptionsMap.size !== 0 ) { - for ( let i = 0; i < hnpartslen; i++ ) { - const hn = hnParts.slice(i).join('.'); - const excepted = exceptionsMap.get(hn); - if ( excepted ) { tonotdoIndices.push(...excepted); } - } - exceptionsMap.clear(); -} - -// Hostname-based -if ( hostnamesMap.size !== 0 ) { - const collectArgIndices = hn => { - let argsIndices = hostnamesMap.get(hn); - if ( argsIndices === undefined ) { return; } - if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; } +const collectArgIndices = (hn, map, out) => { + let argsIndices = map.get(hn); + if ( argsIndices === undefined ) { return; } + if ( typeof argsIndices !== 'number' ) { for ( const argsIndex of argsIndices ) { - if ( tonotdoIndices.includes(argsIndex) ) { continue; } - todoIndices.add(argsIndex); + out.add(argsIndex); } - }; - for ( let i = 0; i < hnpartslen; i++ ) { - const hn = hnParts.slice(i).join('.'); - collectArgIndices(hn); + } else { + out.add(argsIndices); } - collectArgIndices('*'); - hostnamesMap.clear(); -} +}; -// Entity-based -if ( entitiesMap.size !== 0 ) { - const n = hnpartslen - 1; - for ( let i = 0; i < n; i++ ) { - for ( let j = n; j > i; j-- ) { - const en = hnParts.slice(i,j).join('.'); - let argsIndices = entitiesMap.get(en); - if ( argsIndices === undefined ) { continue; } - if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; } - for ( const argsIndex of argsIndices ) { - if ( tonotdoIndices.includes(argsIndex) ) { continue; } - todoIndices.add(argsIndex); +const indicesFromHostname = (hostname, suffix = '') => { + const hnParts = hostname.split('.'); + const hnpartslen = hnParts.length; + if ( hnpartslen === 0 ) { return; } + for ( let i = 0; i < hnpartslen; i++ ) { + const hn = `${hnParts.slice(i).join('.')}${suffix}`; + collectArgIndices(hn, hostnamesMap, todoIndices); + collectArgIndices(hn, exceptionsMap, tonotdoIndices); + } + if ( hasEntities ) { + const n = hnpartslen - 1; + for ( let i = 0; i < n; i++ ) { + for ( let j = n; j > i; j-- ) { + const en = `${hnParts.slice(i,j).join('.')}.*${suffix}`; + collectArgIndices(en, hostnamesMap, todoIndices); + collectArgIndices(en, exceptionsMap, tonotdoIndices); } } } - entitiesMap.clear(); -} - -// Apply scriplets -for ( const i of todoIndices ) { - try { $scriptletName$(...argsList[i]); } - catch(ex) {} -} -argsList.length = 0; - -/******************************************************************************/ - }; -// End of code to inject - -/******************************************************************************/ -// 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 entries = (( ) => { + const docloc = document.location; + const origins = [ docloc.origin ]; + if ( docloc.ancestorOrigins ) { + origins.push(...docloc.ancestorOrigins); + } + return origins.map((origin, i) => { + const beg = origin.lastIndexOf('://'); + if ( beg === -1 ) { return; } + const hn = origin.slice(beg+3) + const end = hn.indexOf(':'); + return { hn: end === -1 ? hn : hn.slice(0, end), i }; + }).filter(a => a !== undefined); +})(); +if ( entries.length === 0 ) { return; } -const targetWorld = '$world$'; +const todoIndices = new Set(); +const tonotdoIndices = new Set(); -// Not Firefox -if ( typeof wrappedJSObject !== 'object' || targetWorld === 'ISOLATED' ) { - return uBOL_$scriptletName$(); +indicesFromHostname(entries[0].hn); +if ( hasAncestors ) { + for ( const entry of entries ) { + if ( entry.i === 0 ) { continue; } + indicesFromHostname(entry.hn, '>>'); + } } -// 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$; +// Apply scriplets +for ( const i of todoIndices ) { + if ( tonotdoIndices.has(i) ) { continue; } + try { $scriptletName$(...argsList[i]); } + catch { } } /******************************************************************************/ @@ -170,6 +113,4 @@ if ( typeof wrappedJSObject !== 'object' || targetWorld === 'ISOLATED' ) { // End of local scope })(); -/******************************************************************************/ - void 0; 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/npm/.eslintrc.json b/platform/nodejs/.eslintrc.json similarity index 100% rename from platform/npm/.eslintrc.json rename to platform/nodejs/.eslintrc.json diff --git a/platform/nodejs/build.js b/platform/nodejs/build.js index dbc08437c6dd1..eb22693ff8bf0 100644 --- a/platform/nodejs/build.js +++ b/platform/nodejs/build.js @@ -19,12 +19,7 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -/******************************************************************************/ - import fs from 'fs'; - import { pslInit } from './index.js'; /******************************************************************************/ diff --git a/platform/nodejs/index.js b/platform/nodejs/index.js index 1d39a7d11292e..3b82cb9ab383e 100644 --- a/platform/nodejs/index.js +++ b/platform/nodejs/index.js @@ -19,31 +19,42 @@ Home: https://github.com/gorhill/uBlock */ -/* globals WebAssembly */ +/* globals process */ -'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 +121,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,13 +185,12 @@ 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); await useLists.promise; - useLists.promise = null; // eslint-disable-line require-atomic-updates + useLists.promise = null; // Commit changes snfe.freeze(); @@ -218,6 +229,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 +251,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 } = {}) { @@ -271,7 +285,7 @@ class StaticNetFilteringEngine { // module.exports. Once all included files are written like ES modules, using // export statements, this should no longer be necessary. if ( typeof module !== 'undefined' && typeof exports !== 'undefined' ) { - module.exports = exports; + module.exports = exports; // eslint-disable-line no-undef } export { diff --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..8baec24e47c52 --- /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 { StaticNetFilteringEngine } from '@gorhill/ubo-core'; +import fs from 'fs/promises'; + +/******************************************************************************/ + +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..190d7e8577cde 100644 --- a/platform/npm/package.json +++ b/platform/npm/package.json @@ -1,12 +1,11 @@ { "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", "scripts": { "build": "node build.js", - "lint": "eslint js/ *.js tests/*.js", "test": "c8 --include=index.js --include=js/**/*.js node test.js --mocha", "test-full-battery": "c8 --include=index.js --include=js/**/*.js node test.js --mocha --full-battery", "check-leaks": "mocha --check-leaks tests/leaks.js" @@ -31,12 +30,11 @@ }, "homepage": "https://github.com/gorhill/uBlock#readme", "engines": { - "node": ">=14.0.0", + "node": ">=18.0.0", "npm": ">=6.14.4" }, "devDependencies": { "c8": "^7.12.0", - "eslint": "^8.29.0", "esm-world": "0.1.3", "mocha": "^10.2.0", "scaling-palm-tree": "github:mjethani/scaling-palm-tree#15cf1ab37e038771e1ff8005edc46d95f176739f" diff --git a/platform/npm/test.js b/platform/npm/test.js index 5b4401e5945d6..25ff9e74302ec 100644 --- a/platform/npm/test.js +++ b/platform/npm/test.js @@ -19,15 +19,10 @@ Home: https://github.com/gorhill/uBlock */ -/* eslint-disable-next-line no-redeclare */ /* globals process */ -'use strict'; - -/******************************************************************************/ - -import { spawn } from "child_process"; import { promisify } from 'util'; +import { spawn } from "child_process"; /******************************************************************************/ diff --git a/platform/opera/manifest.json b/platform/opera/manifest.json index 196c171726670..6b9f0e015c453 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": "79.0", "name": "uBlock Origin", "options_page": "dashboard.html", "permissions": [ diff --git a/src/1p-filters.html b/src/1p-filters.html index bc08479c5c2e4..d35124f21dcb9 100644 --- a/src/1p-filters.html +++ b/src/1p-filters.html @@ -3,6 +3,7 @@ + uBlock — Your filters diff --git a/src/3p-filters.html b/src/3p-filters.html index c9123cc9dfdf6..c7db3b7bfb39f 100644 --- a/src/3p-filters.html +++ b/src/3p-filters.html @@ -3,6 +3,7 @@ + uBlock — Filter lists diff --git a/src/_locales/ar/messages.json b/src/_locales/ar/messages.json index b2c204d3abefd..eaf1cc271a263 100644 --- a/src/_locales/ar/messages.json +++ b/src/_locales/ar/messages.json @@ -100,7 +100,7 @@ "description": "English: or" }, "popupBlockedOnThisPage_v2": { - "message": "محجوب من هذه الصفحة", + "message": "محجوب على هذه الصفحة", "description": "For the new mobile-friendly popup design" }, "popupBlockedSinceInstall_v2": { @@ -128,7 +128,7 @@ "description": "Tooltip used for the logger icon in the panel" }, "popupTipReport": { - "message": "التقرير عن مُشكلة في الموقع", + "message": "الإبلاغ عن مشكلة في هذا الموقع", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipNoPopups": { @@ -188,7 +188,7 @@ "description": "Tooltip for the no-scripting per-site switch" }, "popupNoPopups_v2": { - "message": "الإطارات المنبثقة", + "message": "نوافذ منبثقة", "description": "Caption for the no-popups per-site switch" }, "popupNoLargeMedia_v2": { @@ -196,7 +196,7 @@ "description": "Caption for the no-large-media per-site switch" }, "popupNoCosmeticFiltering_v2": { - "message": "إعادات الفلاتر التجميلية العمومية", + "message": "المرشحات التجميلية", "description": "Caption for the no-cosmetic-filtering per-site switch" }, "popupNoRemoteFonts_v2": { @@ -272,11 +272,11 @@ "description": "appears in popup" }, "popupVersion": { - "message": "نسخة", + "message": "الإصدار", "description": "Example of use: Version 1.26.4" }, "popup3pScriptFilter": { - "message": "سكربت", + "message": "برنامَج نصي", "description": "Appears as an option to filter out firewall rows" }, "popup3pFrameFilter": { @@ -312,7 +312,7 @@ "description": "English: Click, Ctrl-click" }, "pickerContextMenuEntry": { - "message": "إحجب العنصر...", + "message": "حجب العنصر...", "description": "An entry in the browser's contextual menu" }, "settingsCollapseBlockedPrompt": { @@ -340,7 +340,7 @@ "description": "Section for controlling user interface appearance" }, "settingsThemeLabel": { - "message": "المظاهر", + "message": "السمة", "description": "Label for checkbox to enable a custom dark theme" }, "settingsThemeAccent0Label": { @@ -444,7 +444,7 @@ "description": "English: Parse and enforce Adblock+ element hiding filters." }, "3pParseAllABPHideFiltersInfo": { - "message": "الفلاتر التجميلية تعمل لإزالة العناصر في صفحة الويب التي تعتبر إزعاج بصريًا و تلك التي لا يمكن حجبها عن طريق محركات التصفية القائمة على طلبات الشبكة.", + "message": "التشريحات التجميلية تعمل لإزالة العناصر في صفحة الويب التي تعتبر إزعاج بصريًا و تلك التي لا يمكن حجبها عن طريق محركات التشريحات القائمة على طلبات الشبكة.", "description": "Describes the purpose of the 'Parse and enforce cosmetic filters' feature." }, "3pIgnoreGenericCosmeticFilters": { @@ -452,11 +452,11 @@ "description": "This will cause uBO to ignore all generic cosmetic filters." }, "3pIgnoreGenericCosmeticFiltersInfo": { - "message": "الفلاتر التجميلية العمومية هي الفلاتر التجميلية التي تنطبق على كل مواقع الإنترنت. تفعيل هذا الخيار سوف يترك مساحة أقل من الذاكرة و قوة المعالجة للإستعمال من قبل صفحات الويب كنتيجة لمعالجة الفلاتر التجميلية العمومية.\n\nمن الأفضل تفعيل هذا الخيار على الأجهزة الأقل قوة.", + "message": "التشريحات التجميلية العمومية هي الفلاتر التجميلية التي تنطبق على كل مواقع الإنترنت. تفعيل هذا الخيار سوف يترك مساحة أقل من الذاكرة و قوة المعالجة للإستعمال من قبل صفحات الويب كنتيجة لمعالجة التشريحات التجميلية العمومية.\n\nمن الأفضل تفعيل هذا الخيار على الأجهزة الأقل قوة.", "description": "Describes the purpose of the 'Ignore generic cosmetic filters' feature." }, "3pSuspendUntilListsAreLoaded": { - "message": "تعليق نشاط الشبكة حتى يتم تحميل كافة قوائم عوامل التصفية", + "message": "تعليق نشاط الشبكة حتى يتم تحميل كافة قوائم عوامل التشريحات", "description": "A checkbox in the 'Filter lists' pane" }, "3pListsOfBlockedHostsHeader": { @@ -540,15 +540,15 @@ "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { - "message": "تفعيل تصفياتي المخصصة", + "message": "مكّن تشريحاتي المخصصة", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { - "message": "السماح بالفلاتر المخصصة التي تتطلب الثقة", + "message": "السماح بالتشريحات المخصصة التي تتطلب الثقة", "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { - "message": "استيراد و إضافة", + "message": "استورد وألحق…", "description": "Button in the 'My filters' pane" }, "1pExport": { @@ -592,7 +592,7 @@ "description": "Will discard manually-edited content and exit manual-edit mode" }, "rulesImport": { - "message": "الاستيراد من ملف...", + "message": "استورد من ملف...", "description": "" }, "rulesExport": { @@ -632,11 +632,11 @@ "description": "A concise description of the 'Trusted sites' pane." }, "whitelistImport": { - "message": "استيراد و إضافة", + "message": "استورد وألحق…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { - "message": "تصدير", + "message": "صدّر…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExportFilename": { @@ -676,11 +676,11 @@ "description": "Appears in the logger's tab selector" }, "loggerReloadTip": { - "message": "إعادة تحميل محتوى علامة التبويب", + "message": "أعد تحميل محتوى علامة التبويب", "description": "Tooltip for the reload button in the logger page" }, "loggerDomInspectorTip": { - "message": "تفعيل أو تعطيل مراقب DOM", + "message": "بدّل فاحص DOM", "description": "Tooltip for the DOM inspector button in the logger page" }, "loggerPopupPanelTip": { @@ -692,11 +692,11 @@ "description": "Tooltip for the top-right info label in the logger page" }, "loggerClearTip": { - "message": "امسح السجلات", + "message": "امسح المُسجّل", "description": "Tooltip for the eraser in the logger page; used to blank the content of the logger" }, "loggerPauseTip": { - "message": "ايقاف التسجيل مؤقتا (استبعاد كل البيانات الواردة) ", + "message": "أوقف المُسجّل مؤقتا (استبعاد كل البيانات الواردة) ", "description": "Tooltip for the pause button in the logger page" }, "loggerUnpauseTip": { @@ -704,7 +704,7 @@ "description": "Tooltip for the play button in the logger page" }, "loggerRowFiltererButtonTip": { - "message": "تبديل ترشيح بيانات التسجيل ", + "message": "بدّل ترشيح المُسجّل ", "description": "Tooltip for the row filterer button in the logger page" }, "logFilterPrompt": { @@ -748,11 +748,11 @@ "description": "Small header to identify the 'Details' pane for a specific logger entry" }, "loggerEntryDetailsFilter": { - "message": "فلتر", + "message": "المرشّح", "description": "Label to identify a filter field" }, "loggerEntryDetailsFilterList": { - "message": "قائمة الفلتر", + "message": "قائمة المرشحات", "description": "Label to identify a filter list field" }, "loggerEntryDetailsRule": { @@ -832,15 +832,15 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringFinderSentence1": { - "message": "فلتر ثابت {{filter}} موجود في:", + "message": "تصفية ثابتة {{filter}} موجود في:", "description": "Below this sentence, the filter list(s) in which the filter was found" }, "loggerStaticFilteringFinderSentence2": { - "message": "الفلتر الثابت لا يوجد في أي من قوائم الفلاتر المفعلة", + "message": "الترشيح الثابت لا يوجد في أي من قوائم التشريحات المفعلة", "description": "Message to show when a filter cannot be found in any filter lists" }, "loggerSettingDiscardPrompt": { - "message": "مدخلات السجل التي لا تطابق أيا من المعايير ستحذف تلقائيا:", + "message": "مدخلات المُسجّل التي لا تطابق أيا من المعايير ستتجاهل تلقائيا:", "description": "Logger setting: A sentence to describe the purpose of the settings below" }, "loggerSettingPerEntryMaxAge": { @@ -852,7 +852,7 @@ "description": "A logger setting" }, "loggerSettingPerTabMaxEntries": { - "message": "أبق بحد أقصى على {{input}} مدخلات في كل تبويبة", + "message": "أبق بحد أقصى على {{input}} مدخلات في كل لسان", "description": "A logger setting" }, "loggerSettingPerEntryLineCount": { @@ -924,7 +924,7 @@ "description": "First paragraph of 'Questions and support' section in Support pane" }, "supportS3H": { - "message": "تصفية المسائل/موقع الويب معطل", + "message": "تشريح المسائل/موقع الويب معطوب", "description": "Header of 'Filter issues' section in Support pane" }, "supportS3P1": { @@ -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,26 @@ "message": "تقدّم", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "الصفحة المحظورة تريد إعادة توجيهك إلى موقع آخر. إذا اخترت المتابعة، فسوف تنتقل مباشرة إلى: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "السبب:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "ضار", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "متتبع", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "سيئ السمعة", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "التصدير إلى سحابة التخزين", "description": "tooltip" @@ -1244,7 +1268,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..d94ab38a6d46a 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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Bulud yaddaşa göndər", "description": "tooltip" diff --git a/src/_locales/be/messages.json b/src/_locales/be/messages.json index bb7a458505742..b76f0339a3a5d 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": { @@ -228,7 +228,7 @@ "description": "Tooltip when hovering over the padlock in the dynamic filtering pane." }, "popupTipRevertRules": { - "message": "Націсніце, каб скасаваць змены.", + "message": "Націсніце, каб вярнуць змены.", "description": "Tooltip when hovering over the eraser in the dynamic filtering pane." }, "popupAnyRulePrompt": { @@ -252,7 +252,7 @@ "description": "" }, "popup1pScriptRulePrompt": { - "message": "уласныя скрыпты", + "message": "Асноўныя скрыпты", "description": "" }, "popup3pScriptRulePrompt": { @@ -260,7 +260,7 @@ "description": "" }, "popup3pFrameRulePrompt": { - "message": "староннія рамкі", + "message": "староннія фрэймы", "description": "" }, "popupHitDomainCountPrompt": { @@ -308,7 +308,7 @@ "description": "English: Cosmetic filters" }, "pickerCosmeticFiltersHint": { - "message": "Клік, Ctrl-клік", + "message": "Націсканне, Ctrl + націсканне", "description": "English: Click, Ctrl-click" }, "pickerContextMenuEntry": { @@ -424,7 +424,7 @@ "description": "Appears at the top of the _3rd-party filters_ pane" }, "3pListsOfBlockedHostsPerListStats": { - "message": "{{used}} выкарыстана з {{total}}", + "message": "Выкарыстана: {{used}} з {{total}}", "description": "Appears aside each filter list in the _3rd-party filters_ pane" }, "3pAutoUpdatePrompt1": { @@ -740,7 +740,7 @@ "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltin3p": { - "message": "старонні", + "message": "староннія", "description": "A keyword in the built-in row filtering expression" }, "loggerEntryDetailsHeader": { @@ -796,7 +796,7 @@ "description": "Small header to identify the static filtering section" }, "loggerStaticFilteringSentence": { - "message": "{{action}} сеткавыя запыты {{type}}, {{br}}URL-адрас якіх супадае з {{url}} {{br}}і паходзяць з {{origin}},{{br}}{{importance}} ёсць адпаведны фільтр-вынятак.", + "message": "{{action}} сеткавыя запыты {{type}}, {{br}}URL-адрас якіх супадае з {{url}} {{br}}і якія паходзяць з {{origin}},{{br}}{{importance}} з'яўляюцца адпаведным фільтрам выключэння.", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartBlock": { @@ -932,11 +932,11 @@ "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { - "message": "Важна: Пазбягайце выкарыстання іншых блакавальнікаў аналагічнага прызначэння разам з uBlock Origin, паколькі гэта можа прывесці да праблем з фільтрамі на пэўных сайтах.", + "message": "Важна: Пазбягайце выкарыстання іншых блакавальнікаў падобнага прызначэння разам з uBlock Origin, паколькі гэта можа прывесці да праблем з фільтрамі на пэўных сайтах.", "description": "Second paragraph of 'Filter issues' section in Support pane" }, "supportS3P3": { - "message": "Парада: Упэўніцеся, што вашы спісы фільтраў абноўленыя. Логер — галоўны інструмент для дыягностыкі праблем, звязаных з фільтрамі.", + "message": "Парада: Пераканайцеся, што вашы спісы фільтраў знаходзяцца ў актуальным стане. Рэгістратар — гэта галоўны інструмент для дыягностыкі праблем, якія звязаны з фільтрамі.", "description": "Third paragraph of 'Filter issues' section in Support pane" }, "supportS4H": { @@ -956,7 +956,7 @@ "description": "First paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS5P2": { - "message": "Важна: Патэнцыйна прыватная або адчувальная інфармацыя тыпова рэдагуецца. Адрэдагаваная інфармацыя можа зрабіць цяжэйшым вырашэнне праблемы.", + "message": "Важна: Патэнцыйна прыватная або канфідэнцыяльныя зветскі прадвызначана рэдагуюцца. Адрэдагаваныя звесткі могуць ускладніць вырашэнне праблемы.", "description": "Second paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS6H": { @@ -984,7 +984,7 @@ "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { - "message": "-- Выберыце запіс праблемы --", + "message": "-- Выберыце праблему --", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { @@ -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" @@ -1060,7 +1064,7 @@ "description": "Shown in the About pane" }, "aboutCDNsInfo": { - "message": "Калі спіс фільтраў патрабуе абнаўлення, выкарыстоўваецца выпадкова выбраная сетка CDN", + "message": "Пры абнаўленні спіса фільтраў выкарыстоўваецца CDN, які выбіраецца выпадковым чынам", "description": "Shown in the About pane" }, "aboutBackupDataButton": { @@ -1096,7 +1100,7 @@ "description": "English: Network error: {{msg}}" }, "subscriberConfirm": { - "message": "Дадаць наступны URL-адрас да вашага спісу фільтраў?\n\nНазва: \"{{title}}\"\nURL: {{url}}", + "message": "Дадаць наступны URL-адрас да вашага спіса фільтраў?\n\nНазва: \"{{title}}\"\nURL-адрас: {{url}}", "description": "No longer used" }, "subscribeButton": { @@ -1108,7 +1112,7 @@ "description": "English: a minute ago" }, "elapsedManyMinutesAgo": { - "message": "{{value}} хвілін(ы) таму", + "message": "Хвілін таму: {{value}}", "description": "English: {{value}} minutes ago" }, "elapsedOneHourAgo": { @@ -1116,7 +1120,7 @@ "description": "English: an hour ago" }, "elapsedManyHoursAgo": { - "message": "{{value}} гадзін(ы) таму", + "message": "Гадзін таму: {{value}}", "description": "English: {{value}} hours ago" }, "elapsedOneDayAgo": { @@ -1124,7 +1128,7 @@ "description": "English: a day ago" }, "elapsedManyDaysAgo": { - "message": "{{value}} дні таму", + "message": "Дзён таму: {{value}}", "description": "English: {{value}} days ago" }, "showDashboardButton": { @@ -1187,6 +1191,26 @@ "message": "Працягнуць", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Заблакаваная старонка мае намер перанакіраваць на іншы сайт. Калі вырашыце працягнуць, вы пяройдзеце непасрэдна да: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "Падстава:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Шкодная актыўнасць", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Трэкер", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Сумнеўны змест", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Экспартаваць у воблачнае сховішча", "description": "tooltip" diff --git a/src/_locales/bg/messages.json b/src/_locales/bg/messages.json index aaff8db583deb..b0d4ddaa22744 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,26 @@ "message": "Продължаване", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Блокираната страница иска да Ви пренасочи към друг сайт. Ако изберете да продължите, ще отидете директно на: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "Причина:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Злонамерена", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Проследяване", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Неблагонадеждна", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Изнасяне в облачно хранилище", "description": "tooltip" diff --git a/src/_locales/bn/messages.json b/src/_locales/bn/messages.json index de82ca4dee471..ea9b8f66667b4 100644 --- a/src/_locales/bn/messages.json +++ b/src/_locales/bn/messages.json @@ -64,7 +64,7 @@ "description": "Title for the asset viewer page" }, "advancedSettingsPageName": { - "message": "উন্নত সেটিংস", + "message": "অ্যাডভান্সড সেটিংস", "description": "Title for the advanced settings page" }, "popupPowerSwitchInfo": { @@ -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,26 @@ "message": "এগিয়ে যান", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "ব্লককৃত পাতাটি আরেকটি ওয়েবসাইটে নেয়। এগিয়ে যেতে চাইলে, সরাসরি এই জায়গায় যাবে: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "কারণ:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "ক্ষতিকারক", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "ট্র্যাকার", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "অখ্যাতিপূর্ণ", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "ক্লাউড সঞ্চয়ে রপ্তানি করুন", "description": "tooltip" diff --git a/src/_locales/br_FR/messages.json b/src/_locales/br_FR/messages.json index 2a27e9f019281..04e3bc91715df 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": { @@ -356,7 +356,7 @@ "description": "Checkbox to let user access advanced, technical features" }, "settingsPrefetchingDisabledPrompt": { - "message": "Diweredekaat ar \"rak-lenn\", pe diougan an oberoù war ar rouedad (evit ma ne gennaskfe ket ar rekedoù rouedad stanket)", + "message": "Diweredekaat ar \"rak-lenn\", pe diougan an oberoù war ar rouedad (evit ma ne gennaskfe ket rekedoù ar rouedadoù stanket)", "description": "English: " }, "settingsHyperlinkAuditingDisabledPrompt": { @@ -376,7 +376,7 @@ "description": "" }, "settingsNoCosmeticFilteringPrompt": { - "message": "Lazhañ ar silañ kenedel", + "message": "Lazhañ ar siloù kenedel", "description": "" }, "settingsNoLargeMediaPrompt": { @@ -476,7 +476,7 @@ "description": "Filter lists section name" }, "3pGroupPrivacy": { - "message": "Prevezded", + "message": "Buhez prevez", "description": "Filter lists section name" }, "3pGroupMalware": { @@ -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": "Notennoù diwar-benn an toupinoù", "description": "Filter lists section name" }, "3pGroupAnnoyances": { @@ -928,7 +928,7 @@ "description": "Header of 'Filter issues' section in Support pane" }, "supportS3P1": { - "message": "Danevellit kudennoù silañ e lec'hiennoù resis zo e-barzh roll evezhiañ kudennoù uBlockOrigin/uAssets. Ur c'hont GitHub zo rekis.", + "message": "Danevellit kudennoù ar siloù e lec'hiennoù resis e-barzh uBlockOrigin/uAssets roll evezhiañ kudennoù. Ur c'hont GitHub zo rekis.", "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Evit nompas sammañ ar genlabourerien a-youl vat gant meur a zanevell heñvel, gwiriit ma n'eo ket bet danevellet ho kudenn en ar-raok mar plij.", + "message": "Evit nompas sammañ ar genlabourerien a-youl vat gant meur a zanevell heñvel, gwiriit ma n'eo ket bet danevellet ho kudenn en a-raok mar plij.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1000,7 +1000,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { - "message": "Kudennoù a-fed prevezded he deus", + "message": "Kudennoù a-fed ar vuhez prevez he deus", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { @@ -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": "Kas a ra da veziantoù droukyoulet pe d'an higennañ niverel", + "description": "An entry in the widget used to select the type of issue" + }, "supportS6Checkbox1": { "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" @@ -1024,7 +1028,7 @@ "description": "Text for 'Unredact' button" }, "aboutPrivacyPolicy": { - "message": "Politikerezh prevezded", + "message": "Politikerezh ar vuhez prevez", "description": "Link to privacy policy on GitHub (English)" }, "aboutChangelog": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Abeg:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malisius", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Heulier", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Douetus", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Ezporzhiañ etrezek stokañ ar goumoulenn (cloud)", "description": "tooltip" @@ -1260,7 +1284,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..37104b1a3ee89 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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Izvezi u cloud pohranu", "description": "tooltip" @@ -1264,7 +1288,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..c1823bd0eb676 100644 --- a/src/_locales/ca/messages.json +++ b/src/_locales/ca/messages.json @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Crea un informe nou", + "message": "Crea un informe nou al GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Cerca d'informes semblants", + "message": "Cerca informes similars al GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Per evitar carregar els voluntaris amb informes duplicats, verifiqueu que el problema encara no s'hagi notificat.", + "message": "Per a evitar la sobrecàrrega del nostre voluntariat amb informes duplicats, verifiqueu abans que el problema encara no s'ha notificat. Nota: en fer clic, enviareu la pàgina causant al nostre GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Motiu:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Maliciós", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Seguidor", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "De mala reputació", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exporta a un servei al núvol", "description": "tooltip" @@ -1264,7 +1288,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..2a895a3bfb813 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": { @@ -1168,7 +1172,7 @@ "description": "English: Close this window" }, "docblockedDontWarn": { - "message": "Znova mě nevarujte ohladně této stránky", + "message": "Nevarujte mě znovu o této stránce", "description": "Label for checkbox in document-blocked page" }, "docblockedProceed": { @@ -1187,6 +1191,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Důvod:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Zlomyslný", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Sledovač", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Nereputabilní", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exportovat do cloudového úložiště", "description": "tooltip" diff --git a/src/_locales/cv/messages.json b/src/_locales/cv/messages.json index aec33ebe8dfc8..c5b11cea5f9c0 100644 --- a/src/_locales/cv/messages.json +++ b/src/_locales/cv/messages.json @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff --git a/src/_locales/cy/messages.json b/src/_locales/cy/messages.json index 7152ef93ed9dd..3e3b778437bea 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": { @@ -540,7 +540,7 @@ "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { - "message": "Enable my custom filters", + "message": "Galluogi fy hidlyddion addasedig", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { @@ -548,7 +548,7 @@ "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { - "message": "Import and append…", + "message": "Mewnforio ac atodi...", "description": "Button in the 'My filters' pane" }, "1pExport": { @@ -560,19 +560,19 @@ "description": "English: my-ublock-static-filters_{{datetime}}.txt" }, "1pApplyChanges": { - "message": "Apply changes", + "message": "Rhoi'r newidiadau ar waith", "description": "English: Apply changes" }, "rulesPermanentHeader": { - "message": "Permanent rules", + "message": "Rheolau parhaol", "description": "header" }, "rulesTemporaryHeader": { - "message": "Temporary rules", + "message": "Rheolau dros dro", "description": "header" }, "rulesRevert": { - "message": "Revert", + "message": "Gwrthdroi", "description": "This will remove all temporary rules" }, "rulesCommit": { @@ -592,7 +592,7 @@ "description": "Will discard manually-edited content and exit manual-edit mode" }, "rulesImport": { - "message": "Import from file…", + "message": "Mewnforio o ffeil...", "description": "" }, "rulesExport": { @@ -632,7 +632,7 @@ "description": "A concise description of the 'Trusted sites' pane." }, "whitelistImport": { - "message": "Import and append…", + "message": "Mewnforio ac atodi...", "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { @@ -644,7 +644,7 @@ "description": "The default filename to use for import/export purpose" }, "whitelistApply": { - "message": "Apply changes", + "message": "Rhoi'r newidiadau ar waith", "description": "English: Apply changes" }, "logRequestsHeaderType": { @@ -780,7 +780,7 @@ "description": "Label to identify the URL of an entry" }, "loggerURLFilteringHeader": { - "message": "URL rule", + "message": "Rheol URL", "description": "Small header to identify the dynamic URL filtering section" }, "loggerURLFilteringContextLabel": { @@ -820,15 +820,15 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartAnyOrigin": { - "message": "from anywhere", + "message": "o unrhyw le", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartNotImportant": { - "message": "except when", + "message": "ac eithrio pan", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartImportant": { - "message": "even if", + "message": "hyd yn oed os", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringFinderSentence1": { @@ -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": { @@ -948,7 +948,7 @@ "description": "First paragraph of 'Bug report' section in Support pane" }, "supportS5H": { - "message": "Troubleshooting Information", + "message": "Gwybodaeth datrys problemau", "description": "Header of 'Troubleshooting Information' section in Support pane" }, "supportS5P1": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -1011,8 +1011,12 @@ "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”)", + "message": "Rhoi label “NSFW” (“Not Safe For Work”) ar y dudalen we", "description": "A checkbox to use for NSFW sites" }, "supportRedact": { @@ -1028,7 +1032,7 @@ "description": "Link to privacy policy on GitHub (English)" }, "aboutChangelog": { - "message": "Changelog", + "message": "Cofnod newidiadau", "description": "" }, "aboutCode": { @@ -1052,7 +1056,7 @@ "description": "Link text to uBO's own filter lists repo" }, "aboutDependencies": { - "message": "External dependencies (GPLv3-compatible):", + "message": "Gofynion allanol (cydnaws â GPLv3):", "description": "Shown in the About pane" }, "aboutCDNs": { @@ -1064,7 +1068,7 @@ "description": "Shown in the About pane" }, "aboutBackupDataButton": { - "message": "Back up to file…", + "message": "Copïo wrth gefn i ffeil...", "description": "Text for button to create a backup of all settings" }, "aboutBackupFilename": { @@ -1072,11 +1076,11 @@ "description": "English: my-ublock-backup_{{datetime}}.txt" }, "aboutRestoreDataButton": { - "message": "Restore from file…", + "message": "Adfer o ffeil...", "description": "English: Restore from file..." }, "aboutResetDataButton": { - "message": "Reset to default settings…", + "message": "Ailosod y gosodiadau i'r rhagosodiad...", "description": "English: Reset to default settings..." }, "aboutRestoreDataConfirm": { @@ -1092,7 +1096,7 @@ "description": "Message asking user to confirm reset" }, "errorCantConnectTo": { - "message": "Network error: {{msg}}", + "message": "Gwall rhwydwaith: {{msg}}", "description": "English: Network error: {{msg}}" }, "subscriberConfirm": { @@ -1136,7 +1140,7 @@ "description": "Firefox/Fennec-specific: Show Logger" }, "fennecMenuItemBlockingOff": { - "message": "off", + "message": "na", "description": "Firefox-specific: appears as 'uBlock₀ (off)'" }, "docblockedTitle": { @@ -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": "Mae uBlock Origin wedi atal y dudalen ganlynol rhag llwytho:", "description": "Used in the strict-blocking page" }, "docblockedPrompt2": { @@ -1152,7 +1156,7 @@ "description": "Used in the strict-blocking page" }, "docblockedNoParamsPrompt": { - "message": "without parameters", + "message": "heb baramedrau", "description": "label to be used for the parameter-less URL: https://cloud.githubusercontent.com/assets/585534/9832014/bfb1b8f0-593b-11e5-8a27-fba472a5529a.png" }, "docblockedFoundIn": { @@ -1168,7 +1172,7 @@ "description": "English: Close this window" }, "docblockedDontWarn": { - "message": "Don't warn me again about this site", + "message": "Peidio â'm rhybuddio eto am y wefan hon", "description": "Label for checkbox in document-blocked page" }, "docblockedProceed": { @@ -1187,6 +1191,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" @@ -1216,15 +1240,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": { @@ -1288,7 +1312,7 @@ "description": "short for 'gigabytes'" }, "clickToLoad": { - "message": "Click to load", + "message": "Clicio i lwytho", "description": "Message used in frame placeholders" }, "linterMainReport": { diff --git a/src/_locales/da/messages.json b/src/_locales/da/messages.json index 061e781a95026..b21025b52078a 100644 --- a/src/_locales/da/messages.json +++ b/src/_locales/da/messages.json @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Opret ny anmeldelse", + "message": "Opret ny anmeldelse på GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find lign. anmeldelser", + "message": "Find lign. anmeldelser på GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "For at undgå at belaste frivillige med dubletanmeldelser, så tjek venligst, at problemet ikke allerede er anmeldt.", + "message": "For at undgå at bebyrde frivillige med dubletanmeldelser, så tjek venligst, at problematikken ikke allerede er anmeldt. Bemærk: Ved at klikke på knappen, sendes sidens oprindelse til GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Årsag:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Ondsindet", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Ikke-velrenommeret", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Eksportér til Skylager", "description": "tooltip" diff --git a/src/_locales/de/messages.json b/src/_locales/de/messages.json index 473673525f79d..9a87dc09dcc52 100644 --- a/src/_locales/de/messages.json +++ b/src/_locales/de/messages.json @@ -308,7 +308,7 @@ "description": "English: Cosmetic filters" }, "pickerCosmeticFiltersHint": { - "message": "Klick, Strg-Klick", + "message": "Klick, Strg+Klick", "description": "English: Click, Ctrl-click" }, "pickerContextMenuEntry": { @@ -548,7 +548,7 @@ "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { - "message": "Importieren und anfügen …", + "message": "Importieren und ergänzen …", "description": "Button in the 'My filters' pane" }, "1pExport": { @@ -632,7 +632,7 @@ "description": "A concise description of the 'Trusted sites' pane." }, "whitelistImport": { - "message": "Importieren und anfügen …", + "message": "Importieren und ergänzen …", "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { @@ -888,7 +888,7 @@ "description": "Label for radio-button to pick export format" }, "loggerExportEncodePlain": { - "message": "Einfach", + "message": "Reiner Text", "description": "Label for radio-button to pick export text format" }, "loggerExportEncodeMarkdown": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Neuen Bericht erstellen", + "message": "Neue Meldung auf GitHub erstellen", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Ähnliche Berichte suchen", + "message": "Ähnliche Meldungen auf GitHub finden", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Um die Freiwilligen nicht mit doppelten Meldungen zu belasten, vergewissern Sie sich bitte, dass das Problem nicht schon einmal gemeldet wurde.", + "message": "Um die Freiwilligen nicht mit doppelten Meldungen zu überlasten, vergewissern Sie sich bitte, dass das Problem noch nicht gemeldet wurde. Hinweis: Das Anklicken der Schaltfläche übermittelt den Ursprung der Seite an GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Grund:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Schädlich", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Unseriös", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "In den Cloud-Speicher exportieren", "description": "tooltip" diff --git a/src/_locales/el/messages.json b/src/_locales/el/messages.json index ea6a4a6662fe9..871750f30e2ac 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": { @@ -116,7 +116,7 @@ "description": "English: Click to open the dashboard" }, "popupTipZapper": { - "message": "Είσοδος σε λειτουργία εκτέλεσης στοιχείων", + "message": "Είσοδος σε λειτουργία αφαίρεσης στοιχείων", "description": "Tooltip for the element-zapper icon in the popup panel" }, "popupTipPicker": { @@ -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": { @@ -468,7 +468,7 @@ "description": "English: Apply changes" }, "3pGroupDefault": { - "message": "Τοπικά", + "message": "Ενσωματωμένο", "description": "Filter lists section name" }, "3pGroupAds": { @@ -632,11 +632,11 @@ "description": "A concise description of the 'Trusted sites' pane." }, "whitelistImport": { - "message": "Εισαγωγή και προσάρτηση", + "message": "Εισαγωγή και προσθήκη…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { - "message": "Εξαγωγή", + "message": "Εξαγωγή…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExportFilename": { @@ -780,7 +780,7 @@ "description": "Label to identify the URL of an entry" }, "loggerURLFilteringHeader": { - "message": "Κανόνας URL", + "message": "Κανόνας διεύθυνσης URL", "description": "Small header to identify the dynamic URL filtering section" }, "loggerURLFilteringContextLabel": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Δημιουργία νέας αναφοράς", + "message": "Δημιουργία νέας αναφοράς στο Github", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Βρείτε παρόμοιες αναφορές", + "message": "Εύρεση παρόμοιων αναφορών στο GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -940,7 +940,7 @@ "description": "Third paragraph of 'Filter issues' section in Support pane" }, "supportS4H": { - "message": "Αναφορά σφαλμάτων", + "message": "Αναφορά σφάλματος", "description": "Header of 'Bug report' section in Support pane" }, "supportS4P1": { @@ -948,7 +948,7 @@ "description": "First paragraph of 'Bug report' section in Support pane" }, "supportS5H": { - "message": "Πληροφορίες αντιμετώπισης προβλημάτων", + "message": "Πληροφορίες για αντιμετώπιση προβλημάτων", "description": "Header of 'Troubleshooting Information' section in Support pane" }, "supportS5P1": { @@ -960,7 +960,7 @@ "description": "Second paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS6H": { - "message": "Αναφέρετε ένα πρόβλημα φίλτρου", + "message": "Αναφέρετε πρόβλημα φίλτρου", "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { @@ -980,7 +980,7 @@ "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "Η ιστοσελίδα...", + "message": "Η ιστοσελίδα…", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { @@ -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" @@ -1028,7 +1032,7 @@ "description": "Link to privacy policy on GitHub (English)" }, "aboutChangelog": { - "message": "Αρχείο καταγραφής αλλαγών", + "message": "Αρχείο αλλαγών", "description": "" }, "aboutCode": { @@ -1060,7 +1064,7 @@ "description": "Shown in the About pane" }, "aboutCDNsInfo": { - "message": "Ένα τυχαία επιλεγμένο CDN χρησιμοποιείται όταν πρέπει να ενημερωθεί μια λίστα φίλτρων", + "message": "Χρησιμοποιείται τυχαία-επιλεγμένο CDN όταν πρέπει να ενημερωθεί μια λίστα φίλτρων", "description": "Shown in the About pane" }, "aboutBackupDataButton": { @@ -1088,7 +1092,7 @@ "description": "Message to display when an error occurred during restore" }, "aboutResetDataConfirm": { - "message": "Όλες οι ρυθμίσεις σας θα καταργηθούν και θα γίνει επανεκκίνηση του uBlock.\n\nΕπαναφορά του uBlock στις εργοστασιακές ρυθμίσεις;", + "message": "Όλες οι ρυθμίσεις σας θα καταργηθούν και θα γίνει επανεκκίνηση του uBlock₀.\n\nΕπαναφορά του uBlock₀ στις αρχικές ρυθμίσεις;", "description": "Message asking user to confirm reset" }, "errorCantConnectTo": { @@ -1187,6 +1191,26 @@ "message": "Συνέχεια", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Η αποκλεισμένη σελίδα θέλει να κάνει ανακατεύθυνση σε άλλο ιστότοπο. Αν επιλέξετε να συνεχίσετε, θα μεταβείτε απευθείας στο: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "Αιτία:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Κακόβουλος ιστότοπος", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Ιχνηλάτης", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Κακόφημος ιστότοπος", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Εξαγωγή στο cloud storage", "description": "tooltip" diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 92fb26065ab9d..0c062100aca1a 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -901,11 +901,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -965,7 +965,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff --git a/src/_locales/en_GB/messages.json b/src/_locales/en_GB/messages.json index 8fd9b46001abc..69968e16765fb 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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff --git a/src/_locales/eo/messages.json b/src/_locales/eo/messages.json index 1d69a1fda396f..8bc3bc7d825f2 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": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Eksporti al nuba konservado", "description": "tooltip" diff --git a/src/_locales/es/messages.json b/src/_locales/es/messages.json index 55bd2e95821f5..206a0fd22222a 100644 --- a/src/_locales/es/messages.json +++ b/src/_locales/es/messages.json @@ -536,7 +536,7 @@ "description": "used as a tooltip for error icon beside a list" }, "1pTrustWarning": { - "message": "No añadir filtros de fuentes no confiables.", + "message": "No añadas filtros de fuentes no confiables.", "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Crear nuevo reporte", + "message": "Crear nuevo reporte en GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Encontrar reportes similares", + "message": "Encontrar reportes similares en GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Para evitar sobrecargar a voluntarios con reportes duplicados, verifica que el problema no haya sido reportado.", + "message": "Para evitar sobrecargar a voluntarios con reportes duplicados, verifica que el problema no haya sido reportado. Nota: al hacer clic en el botón, hará que el origen de la página se envíe a GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Razón:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicioso", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Rastreador", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Mala reputación", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exportar datos a la nube", "description": "tooltip" diff --git a/src/_locales/et/messages.json b/src/_locales/et/messages.json index 5ab8cc917fa23..2186026cfbc55 100644 --- a/src/_locales/et/messages.json +++ b/src/_locales/et/messages.json @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Loo uus aruanne", + "message": "Loo GitHubis uus aruanne", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Leia sarnaseid aruandeid", + "message": "Leia GitHubist sarnaseid aruandeid", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Vabatahtlike koormuse vähendamiseks veendu, et probleemi pole juba teatatud.", + "message": "Vabatahtlike koormuse vähendamiseks palun veendu, et probleemi ei ole juba teatatud. Märkus: nupu klõpsamine saadab lehe aadressi GitHubi.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Põhjus:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Kahtlane", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Jälgija", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Kaak", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Ekspordi pilvehoidlasse", "description": "tooltip" diff --git a/src/_locales/eu/messages.json b/src/_locales/eu/messages.json index b87b777e765fc..f016d13ed9c07 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,26 @@ "message": "Aurrera", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Blokeatutako orrialdeak beste helbide batera berbideratu nahi zaitu. Jarraitu nahi baduzu, zuzenean helbide honetara joango zara: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Esportatu hodei biltegiratzera", "description": "tooltip" diff --git a/src/_locales/fa/messages.json b/src/_locales/fa/messages.json index ef05c734625d9..b48b35e137f3e 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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "دلیل", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "ردیاب", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "صدور به فضای ذخیره سازی ابری", "description": "tooltip" @@ -1260,7 +1284,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 +1320,7 @@ "description": "Summary of number of errors as reported by the linter " }, "unprocessedRequestTooltip": { - "message": "Could not filter properly at browser launch. Reload the page to ensure proper filtering.", + "message": "فیلترگذاری به‌درستی در هنگام راه‌اندازی مرورگر انجام نشد. صفحه را دوباره بارگذاری کنید تا از فیلترگذاری صحیح اطمینان حاصل کنید.", "description": "A warning which will appear in the popup panel if needed" }, "dummy": { diff --git a/src/_locales/fi/messages.json b/src/_locales/fi/messages.json index da52acf6d3516..c30fa20c4a457 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": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Luo uusi ilmoitus", + "message": "Luo GitHubiin uusi ilmoitus", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Etsi samankaltaisia ilmoituksia", + "message": "Etsi GitHubista vastaavia ilmoituksia", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -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": { @@ -948,11 +948,11 @@ "description": "First paragraph of 'Bug report' section in Support pane" }, "supportS5H": { - "message": "Vianmääritystiedot", + "message": "Vianselvitystiedot", "description": "Header of 'Troubleshooting Information' section in Support pane" }, "supportS5P1": { - "message": "Alla on teknisiä tietoja, joista voi olla hyötyä vapaaehtoisille, jotka pyrkivät auttamaan ongelmasi ratkaisussa.", + "message": "Alla on teknisiä tietoja, jotka saattavat auttaa ongelmasi ratkonnassa auttavia vapaaehtoisia.", "description": "First paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS5P2": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Välttääksesi vapaaehtoisten kuormittamisen ylimääräisillä ilmoituksilla, tarkista ensin onko ongelmasta jo ilmoitettu.", + "message": "Välttääksesi vapaaehtoisten kuormittamisen ylimääräisillä ilmoituksilla, tarkasta ensin onko ongelmasta jo ilmoitettu. Huomioi: Painikkeen painallus lähettää sivun osoitteen GitHubiin.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Vie pilvitallennustilaan", "description": "tooltip" diff --git a/src/_locales/fil/messages.json b/src/_locales/fil/messages.json index d38e062021d63..6619ba7587160 100644 --- a/src/_locales/fil/messages.json +++ b/src/_locales/fil/messages.json @@ -484,11 +484,11 @@ "description": "Filter lists section name" }, "3pGroupSocial": { - "message": "Social widgets", + "message": "Panlipunang mga widget", "description": "Filter lists section name" }, "3pGroupCookies": { - "message": "Cookie notices", + "message": "Pabatid para sa mga cookie", "description": "Filter lists section name" }, "3pGroupAnnoyances": { @@ -540,11 +540,11 @@ "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { - "message": "Enable my custom filters", + "message": "Paganahin ang mga pasadyang filter", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { - "message": "Allow custom filters requiring trust", + "message": "Hayaan ang mga pansariling filter na kailangan ng tiwala", "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { @@ -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": "Patungo sa badware o 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,26 @@ "message": "Tumuloy", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Nais nitong website na dalhin ka sa iss pang site. Kung tutuloy ka, pupunta ka sa: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "I-export sa imbakan sa cloud", "description": "tooltip" @@ -1264,7 +1288,7 @@ "description": "Label for keyboard shortcut used to toggle cosmetic filtering" }, "toggleJavascript": { - "message": "Toggle JavaScript", + "message": "Paganahin ang JavaScript ", "description": "Label for keyboard shortcut used to toggle no-scripting switch" }, "relaxBlockingMode": { diff --git a/src/_locales/fr/messages.json b/src/_locales/fr/messages.json index fda258990d51f..a67c9f2e4fd38 100644 --- a/src/_locales/fr/messages.json +++ b/src/_locales/fr/messages.json @@ -116,7 +116,7 @@ "description": "English: Click to open the dashboard" }, "popupTipZapper": { - "message": "Entrer en mode Zappeur", + "message": "Entrer en mode Zappeur d'élément", "description": "Tooltip for the element-zapper icon in the popup panel" }, "popupTipPicker": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Créer un rapport", + "message": "Créer un nouveau rapport sur GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Trouver des rapports similaires", + "message": "Trouver des rapports similaires sur GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Pour éviter d'encombrer les contributeurs avec des rapports en double, veuillez vérifier que le problème n'a pas déjà été rapporté.", + "message": "Pour éviter d'encombrer les contributeurs avec des rapports en double, veuillez vérifier que le problème n'a pas déjà été rapporté.\nNote : Cliquer sur le bouton entraînera l'envoi de la page d'origine à GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Motif du blocage :", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malveillant", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Pisteur", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Douteux", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exporter vers le stockage dans le nuage", "description": "tooltip" diff --git a/src/_locales/fy/messages.json b/src/_locales/fy/messages.json index ef97ec15d4891..56649a48728ba 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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reden:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "kweawillich", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "berucht", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Eksportearje nei cloudûnthâld", "description": "tooltip" diff --git a/src/_locales/gl/messages.json b/src/_locales/gl/messages.json index 291dc091324a8..314aba10856b3 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": { @@ -108,7 +108,7 @@ "description": "For the new mobile-friendly popup design" }, "popupDomainsConnected_v2": { - "message": "Dominos conectados", + "message": "Dominios conectados", "description": "For the new mobile-friendly popup design" }, "popupTipDashboard": { @@ -184,7 +184,7 @@ "description": "Tooltip for the no-scripting per-site switch" }, "popupTipNoScripting2": { - "message": "Preme para volver a activar JavaScript nesta web", + "message": "Preme para volver activar JavaScript nesta web", "description": "Tooltip for the no-scripting per-site switch" }, "popupNoPopups_v2": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Razón:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Daniña", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Rastrexo", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Mala reputación", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exportar ó almacenamento na nube", "description": "tooltip" diff --git a/src/_locales/gu/messages.json b/src/_locales/gu/messages.json index 9db2f73145056..1f109b80476de 100644 --- a/src/_locales/gu/messages.json +++ b/src/_locales/gu/messages.json @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff --git a/src/_locales/he/messages.json b/src/_locales/he/messages.json index b036e932ece77..274d15c83be2c 100644 --- a/src/_locales/he/messages.json +++ b/src/_locales/he/messages.json @@ -904,7 +904,7 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "מצא דוחות דומים", + "message": "חיפוש דוחות דומים", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -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,26 @@ "message": "המשך", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "הדף החסום מבקש לעבור לאתר אחר. אם תחליטו להמשיך, תעברו ישירות ל: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "הסיבה:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "זדוני", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "מעקב", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "מפוקפק", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "ייצא לאחסון ענן", "description": "tooltip" diff --git a/src/_locales/hi/messages.json b/src/_locales/hi/messages.json index 4e2cf86c5182b..9343efb4b9118 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,26 @@ "message": "आगे बढ़ें", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "ब्लॉक किया गया पेज किसी दूसरी साइट पर ले जाना चाहता है. अगर आप आगे बढ़ना चुनते हैं, तो आप सीधे इस लिंक को खोल सकते हैं: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "क्लाउड स्टोरेज में भेजें", "description": "tooltip" diff --git a/src/_locales/hr/messages.json b/src/_locales/hr/messages.json index bb5ed413611fd..4af22495b574b 100644 --- a/src/_locales/hr/messages.json +++ b/src/_locales/hr/messages.json @@ -140,11 +140,11 @@ "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoPopups2": { - "message": "Kliknite za ukloniti blokiranje svih pop-up prozora na ovom sajtu", + "message": "Kliknite za ukloniti blokiranje svih pop-up prozora na ovoj stranici", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoLargeMedia": { - "message": "Namjestite blokiranje velikih medijskih elemenata za ovo mjesto", + "message": "Namjestite blokiranje velikih medijskih elemenata za ovu stranicu", "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoLargeMedia1": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Napravi novu prijavu", + "message": "Napravi novu prijavu na GitHub-u", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Nađi slične prijave", + "message": "Nađi slične prijave na GitHub-u", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Kako biste izbjegli opterećivanje volontera duplim prijavama, provjerite nije li problem već prijavljen.", + "message": "Kako biste izbjegli opterećivanje volontera duplim prijavama, provjerite nije li problem već prijavljen. Napomena: klik na gumb uzrokovat će slanje izvorne stranice na GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Razlog:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Zlonamjerno", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Pratioc", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Zloglasno", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Izvezi u pohranu u oblaku", "description": "tooltip" diff --git a/src/_locales/hu/messages.json b/src/_locales/hu/messages.json index b41a850395026..c464637dc0f8c 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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Ok:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Káros", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Nyomkövető", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Rossz hírnevű", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exportálás a felhőszolgáltatásba", "description": "tooltip" @@ -1228,11 +1252,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 +1272,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 +1280,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 +1288,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 +1312,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..8fb8c53306bae 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,26 @@ "message": "Շարունակել", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Արգելափակված կայքը ցանկանում է տեղափոխել Ձեզ ուրիշ կայք։ Եթե ցանկանում եք շարունակել, Դուք անմիջապես կտեղափոխվեք {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Արտահանել առ ամպային պահեստ", "description": "tooltip" diff --git a/src/_locales/id/messages.json b/src/_locales/id/messages.json index 2ac75d90f607f..2da580d92e9cc 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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Ekspor ke penyimpanan awan", "description": "tooltip" diff --git a/src/_locales/it/messages.json b/src/_locales/it/messages.json index c87a90ff97181..6cce7a94ffc6c 100644 --- a/src/_locales/it/messages.json +++ b/src/_locales/it/messages.json @@ -28,7 +28,7 @@ "description": "appears as tab name in dashboard" }, "3pPageName": { - "message": "Filtri di terze parti", + "message": "Liste dei filtri", "description": "appears as tab name in dashboard" }, "1pPageName": { @@ -76,7 +76,7 @@ "description": "Message to be read by screen readers" }, "popupPowerSwitchInfo2": { - "message": "Clicca per attivare uBlock₀ in questo sito.", + "message": "Clicca per abilitare uBlock₀ per questo sito.", "description": "Message to be read by screen readers" }, "popupBlockedRequestPrompt": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Motivo:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Maligno", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Localizzatore", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disdicevole", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Esporta nel cloud", "description": "tooltip" @@ -1240,7 +1264,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 +1284,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 +1320,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..30226d57cb28d 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,26 @@ "message": "続行する", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "ブロックしたページは別のサイトへリダイレクトしようとしています。続行すると次の URL へ移動します: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "クラウドストレージにエクスポートします", "description": "tooltip" diff --git a/src/_locales/ka/messages.json b/src/_locales/ka/messages.json index da9ea635b7a7d..10c0c72200055 100644 --- a/src/_locales/ka/messages.json +++ b/src/_locales/ka/messages.json @@ -68,7 +68,7 @@ "description": "Title for the advanced settings page" }, "popupPowerSwitchInfo": { - "message": "დაწკაპუნება: ამ საიტისთვის uBlock-ის ჩართვა/გამორთვა.\n\nCtrl+დაწკაპუნება: uBlock-ის მხოლოდ ამ გვერდზე გამორთვა.", + "message": "დაწკაპებით: ჩაირთვება/გამოირთვება uBlock ამ საიტზე.\n\nCtrl+დაწკაპებით: გამოირთვება uBlock მხოლოდ ამ გვერდზე.", "description": "English: Click: disable/enable uBlock₀ for this site.\n\nCtrl+click: disable uBlock₀ only on this page." }, "popupPowerSwitchInfo1": { @@ -364,7 +364,7 @@ "description": "English: " }, "settingsWebRTCIPAddressHiddenPrompt": { - "message": "WebRTC-სთვის ხელის შეშლა შიდა IP მისამართის გაჟონვაში", + "message": "WebRTC-ით შიდა IP-მისამართის გამჟღავნების აღკვეთა", "description": "English: " }, "settingPerSiteSwitchGroup": { @@ -388,7 +388,7 @@ "description": "" }, "settingsNoScriptingPrompt": { - "message": "JavaScript-ის გათიშვა", + "message": "გაითიშოს JavaScript", "description": "The default state for the per-site no-scripting switch" }, "settingsNoCSPReportsPrompt": { @@ -536,7 +536,7 @@ "description": "used as a tooltip for error icon beside a list" }, "1pTrustWarning": { - "message": "ფილტრების არიდება არასანდო წყაროებიდან.", + "message": "ნუ დაამატებთ ფილტრებს არასანდო წყაროებიდან.", "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { @@ -944,7 +944,7 @@ "description": "Header of 'Bug report' section in Support pane" }, "supportS4P1": { - "message": "თავად uBlock Origin-ის ხარვეზების მოსახსენებლად, გამოიყენეთ uBlockOrigin/uBlock-issue ხარვეზების აღსარიცხავი. დაგჭირდებათ GitHub-ანგარიში.", + "message": "ხარვეზების მოხსენებისთვის, რომლის წყაროცაა თავად uBlock Origin, გამოიყენეთ uBlockOrigin/uBlock-issue ხარვეზების აღსარიცხავი. დაგჭირდებათ GitHub-ანგარიში.", "description": "First paragraph of 'Bug report' section in Support pane" }, "supportS5H": { @@ -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" @@ -1056,7 +1060,7 @@ "description": "Shown in the About pane" }, "aboutCDNs": { - "message": "uBO-ს კუთვნილი ფილტრები ღიადაა განთავსებული შემდეგ CDN-ებზე:", + "message": "uBO საკუთარ ფილტრებს ღიად ათავსებს მოცემულ CDN-ებზე:", "description": "Shown in the About pane" }, "aboutCDNsInfo": { @@ -1088,7 +1092,7 @@ "description": "Message to display when an error occurred during restore" }, "aboutResetDataConfirm": { - "message": "თქვენ მიერ მითითებული ყველა პარამეტრი წაიშლება და uBlock₀ გაეშვება ხელახლა.\n\nნამდვილად გსურთ uBlock₀-ის ნაგულისხმევ პარამეტრებზე დაბრუნება?", + "message": "თქვენ მიერ მითითებული ყველა პარამეტრი წაიშლება და uBlock₀ გაეშვება ხელახლა.\n\nნამდვილად გსურთ დაბრუნდეს uBlock₀ ნაგულისხმევ პარამეტრებზე?", "description": "Message asking user to confirm reset" }, "errorCantConnectTo": { @@ -1187,6 +1191,26 @@ "message": "მაინც გადასვლა", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "ეს შეზღუდული გვერდი ცდილობს სხვა საიტზე გადაყვანას. თუ განაგრძობთ, პირდაპირ გაიხსნება: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "მიზეზი:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "მავნებელი", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "მეთვალყურე", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "სახელგატეხილი", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "ღრუბლოვან საცავში შენახვა", "description": "tooltip" @@ -1264,7 +1288,7 @@ "description": "Label for keyboard shortcut used to toggle cosmetic filtering" }, "toggleJavascript": { - "message": "JavaScript-ის ჩამრთველი", + "message": "JavaScript – გადამრთველი", "description": "Label for keyboard shortcut used to toggle no-scripting switch" }, "relaxBlockingMode": { diff --git a/src/_locales/kk/messages.json b/src/_locales/kk/messages.json index bd037e0a72ff5..3205a862c7c33 100644 --- a/src/_locales/kk/messages.json +++ b/src/_locales/kk/messages.json @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Бұлтты жадқа экспорттау", "description": "tooltip" diff --git a/src/_locales/kn/messages.json b/src/_locales/kn/messages.json index 7ae8e6ff84e0a..22279279ee7b4 100644 --- a/src/_locales/kn/messages.json +++ b/src/_locales/kn/messages.json @@ -8,7 +8,7 @@ "description": "this will be in the Chrome web store: must be 132 characters or less" }, "dashboardName": { - "message": "uBlock₀ - ಡ್ಯಾಶ್ಬೋರ್ಡ", + "message": "uBlock₀ - ಡ್ಯಾಶ್ಬೋರ್ಡು", "description": "English: uBlock₀ — Dashboard" }, "dashboardUnsavedWarning": { @@ -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,19 +136,19 @@ "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoPopups1": { - "message": "Click to block all popups on this site", + "message": "ಈ ಸೈಟ್‌ನಲ್ಲಿ ಎಲ್ಲಾ ಪಾಪ್‌ಅಪ್‌ಗಳನ್ನು ನಿರ್ಬಂಧಿಸಲು ಕ್ಲಿಕ್ ಮಾಡಿ", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoPopups2": { - "message": "Click to no longer block all popups on this site", + "message": "ಈ ಸೈಟ್‌ನಲ್ಲಿ ಇನ್ನು ಮುಂದೆ ಎಲ್ಲಾ ಪಾಪ್‌ಅಪ್‌ಗಳನ್ನು ನಿರ್ಬಂಧಿಸದಿರಲು ಕ್ಲಿಕ್ ಮಾಡಿ", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoLargeMedia": { - "message": "Toggle the blocking of large media elements for this site", + "message": "ಈ ಸೈಟ್‌ಗಾಗಿ ದೊಡ್ಡ ಮಾಧ್ಯಮ ಅಂಶಗಳ ನಿರ್ಬಂಧಿಸುವಿಕೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ಕ್ಲಿಕ್ ಮಾಡಿ", "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoLargeMedia1": { - "message": "Click to block large media elements on this site", + "message": "ಈ ಸೈಟ್‌ಗಾಗಿ ದೊಡ್ಡ ಮಾಧ್ಯಮ ಅಂಶಗಳ ನಿರ್ಬಂಧಿಸುವಿಕೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ಕ್ಲಿಕ್ ಮಾಡಿ", "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoLargeMedia2": { @@ -160,11 +160,11 @@ "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoCosmeticFiltering1": { - "message": "Click to disable cosmetic filtering on this site", + "message": "ಈ ಸೈಟ್‌ನಲ್ಲಿ ಕಾಸ್ಮೆಟಿಕ್ ಫಿಲ್ಟರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಕ್ಲಿಕ್ ಮಾಡಿ.", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoCosmeticFiltering2": { - "message": "Click to enable cosmetic filtering on this site", + "message": "ಈ ಸೈಟ್‌ನಲ್ಲಿ ಕಾಸ್ಮೆಟಿಕ್ ಫಿಲ್ಟರಿಂಗ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ಕ್ಲಿಕ್ ಮಾಡಿ.", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoRemoteFonts": { @@ -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": { @@ -616,7 +616,7 @@ "description": "English: label for sort option." }, "rulesSortByType": { - "message": "Rule type", + "message": "ನಿಯಮದ ಪ್ರಕಾರ", "description": "English: a sort option for list of rules." }, "rulesSortBySource": { @@ -748,7 +748,7 @@ "description": "Small header to identify the 'Details' pane for a specific logger entry" }, "loggerEntryDetailsFilter": { - "message": "Filter", + "message": "ಫಿಲ್ಟರ್", "description": "Label to identify a filter field" }, "loggerEntryDetailsFilterList": { @@ -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": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" @@ -1272,7 +1296,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..53c728da7c375 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,26 @@ "message": "계속", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "차단된 페이지에서 다른 사이트로 이동하려 합니다. 계속하시면, {{url}} 주소로 바로 이동합니다.", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "사유:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "악성", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "추적기", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "낮은 평판", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "클라우드 저장소로 내보내기", "description": "tooltip" diff --git a/src/_locales/lt/messages.json b/src/_locales/lt/messages.json index a44db57fe1420..4a8e8d9dc8ddb 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": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Eksportuoti į nuotolinę saugyklą", "description": "tooltip" diff --git a/src/_locales/lv/messages.json b/src/_locales/lv/messages.json index c529a68246d4d..ae78a4e8ffda3 100644 --- a/src/_locales/lv/messages.json +++ b/src/_locales/lv/messages.json @@ -20,7 +20,7 @@ "description": "Label for button to prevent navigating away from unsaved changes" }, "dashboardUnsavedWarningIgnore": { - "message": "Ignorēt", + "message": "Neņemt vērā", "description": "Label for button to ignore unsaved changes" }, "settingsPageName": { @@ -76,7 +76,7 @@ "description": "Message to be read by screen readers" }, "popupPowerSwitchInfo2": { - "message": "Klikšķināt, lai šai vietnei ieslēgtu uBlock₀.", + "message": "Klikšķināt, lai šajā vietnē iespējotu uBlock₀.", "description": "Message to be read by screen readers" }, "popupBlockedRequestPrompt": { @@ -448,11 +448,11 @@ "description": "Describes the purpose of the 'Parse and enforce cosmetic filters' feature." }, "3pIgnoreGenericCosmeticFilters": { - "message": "Ignorēt vispārīgos kosmētiskos filtrus", + "message": "Neņemt vērā vispārīgos kosmētiskos aizturētājus", "description": "This will cause uBO to ignore all generic cosmetic filters." }, "3pIgnoreGenericCosmeticFiltersInfo": { - "message": "

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

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

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

Ieteicams izmantot zemas veiktspējas ierīcēm.", + "message": "Vispārīgie kosmētiskie aizturētāji ir tādi kosmētiskie aizturētāji, kurus paredzēts pielietot visās tīmekļvietnēs. Šīs iespējas iespējošana novērsīs tīmekļa lapām pievienoto atmiņas un CPU virstēriņu kā vispārīgo kosmētisko aizturētāju apstrādāšanas iznākumu.\n\nIr ieteicams iespējot šo iespēju mazāk jaudīgās ierīcēs.", "description": "Describes the purpose of the 'Ignore generic cosmetic filters' feature." }, "3pSuspendUntilListsAreLoaded": { @@ -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": { @@ -508,11 +508,11 @@ "description": "Filter lists section name" }, "3pImport": { - "message": "Importēt…", + "message": "Ievietot…", "description": "The label for the checkbox used to import external filter lists" }, "3pExternalListsHint": { - "message": "Vienu URL katrā rindiņā. Rindiņas, kuras sākas ar ‘!’ tiks ignorētas. Nederīgs URL tiks ignorēts bez brīdinājuma.", + "message": "Viens URL katrā rindā. Nederīgi URL netiks ņemti vērā.", "description": "Short information about how to use the textarea to import external filter lists by URL" }, "3pExternalListObsolete": { @@ -552,7 +552,7 @@ "description": "Button in the 'My filters' pane" }, "1pExport": { - "message": "Eksportēt", + "message": "Izgūt…", "description": "Button in the 'My filters' pane" }, "1pExportFilename": { @@ -592,11 +592,11 @@ "description": "Will discard manually-edited content and exit manual-edit mode" }, "rulesImport": { - "message": "Importēt no faila…", + "message": "Ievietot no datnes…", "description": "" }, "rulesExport": { - "message": "Eksportēt uz failu", + "message": "Izgūt datnē…", "description": "Button in the 'My rules' pane" }, "rulesDefaultFileName": { @@ -636,7 +636,7 @@ "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { - "message": "Eksportēt", + "message": "Izgūt…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExportFilename": { @@ -932,7 +932,7 @@ "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { - "message": "Svarīgi: ir jāizvairas no līdzīgu aizturētāju izmantošanas vienlaicīgi ar uBlock Origin, jo tas var radīt aizturēšanas kļūmes noteiktās vietnēs.", + "message": "Svarīgi: ir jāizvairās no līdzīgu aizturētāju izmantošanas vienlaicīgi ar uBlock Origin, jo tas var radīt aizturēšanas kļūmes noteiktās vietnēs.", "description": "Second paragraph of 'Filter issues' section in Support pane" }, "supportS3P3": { @@ -956,7 +956,7 @@ "description": "First paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS5P2": { - "message": "Svarīgi: iespējami privāta vai sensitīva informācija pēc noklusējuma tiek izņemta. Aizvākta informācija var apgrūtināt sarežģījuma atrisināšanu.", + "message": "Svarīgi: iespējami privāta vai jūtīga informācija pēc noklusējuma tiek izņemta. Aizvākta informācija var apgrūtināt sarežģījuma atrisināšanu.", "description": "Second paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS6H": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Iemesls:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Ļaunprātīgas darbības", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Izsekotājs", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Slikta slava", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Eksports uz mākoņdatu glabātuvi", "description": "tooltip" diff --git a/src/_locales/mk/messages.json b/src/_locales/mk/messages.json index 0a7777f9b04aa..f350101f6a485 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,39 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { - "message": "Export to cloud storage", + "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 +1232,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 +1252,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 +1272,7 @@ "description": "Placeholder string for input field used to capture a keyboard shortcut" }, "genericMergeViewScrollLock": { - "message": "Toggle locked scrolling", + "message": "Промени заклучување на скролувањето", "description": "Tooltip for the button used to lock scrolling between the views in the 'My rules' pane" }, "genericCopyToClipboard": { @@ -1256,15 +1280,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 +1296,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 +1312,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..9d6b0cb6dab1f 100644 --- a/src/_locales/ml/messages.json +++ b/src/_locales/ml/messages.json @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "ക്ലൌഡ് സ്റ്റോറേജിലേക്ക് എക്സ്പോര്‍ട്ട്‌ ചെയ്യുക", "description": "tooltip" diff --git a/src/_locales/mr/messages.json b/src/_locales/mr/messages.json index 6530b322480be..b0f355ade34de 100644 --- a/src/_locales/mr/messages.json +++ b/src/_locales/mr/messages.json @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff --git a/src/_locales/ms/messages.json b/src/_locales/ms/messages.json index ed5b060b45f94..1dfa943d00d9e 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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Eksport ke storan awan", "description": "tooltip" @@ -1264,7 +1288,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..5478111eabc1c 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 moduler", "description": "Filter lists section name" }, "3pGroupCookies": { - "message": "Cookie meldinger", + "message": "Infokapselmeldinger", "description": "Filter lists section name" }, "3pGroupAnnoyances": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Opprett ny rapport", + "message": "Opprett ny rapport på GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Finn lignende rapporter", + "message": "Finn lignende rapporter på GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "For å unngå å belaste frivillige med duplikate rapporter, kontroller at problemet ikke allerede er rapportert.", + "message": "For å unngå å belaste de frivillige med dobbeltrapporter, må du kontrollere at problemet ikke allerede har blitt rapportert. Noter: ved å klikke på knappen vil sidens opprinnelse bli sendt til GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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": "Fører til skadelig programvare og/eller 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,26 @@ "message": "Fortsett", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Den blokkerte siden ønsker å omdirigere til et annet nettsted. Hvis du velger å fortsette, vil du navigere direkte til: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Eksporter til nettlagring", "description": "tooltip" diff --git a/src/_locales/nl/messages.json b/src/_locales/nl/messages.json index 554544ccb5437..1f18a0da1e53f 100644 --- a/src/_locales/nl/messages.json +++ b/src/_locales/nl/messages.json @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Nieuwe melding maken", + "message": "Nieuwe melding op GitHub maken", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Soortgelijke meldingen zoeken", + "message": "Soortgelijke meldingen op GitHub zoeken", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Controleer of het probleem niet eerder is gemeld om te voorkomen dat vrijwilligers met dubbele meldingen worden belast.", + "message": "Controleer of het probleem niet eerder is gemeld om te voorkomen dat vrijwilligers met dubbele meldingen worden belast. Noot: op de knop klikken zorgt ervoor dat de oorsprong van de pagina naar GitHub wordt verzonden.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reden:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "kwaadwillend", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "berucht", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exporteren naar cloudopslag", "description": "tooltip" diff --git a/src/_locales/oc/messages.json b/src/_locales/oc/messages.json index 6d141a65722d6..483ecfeda771d 100644 --- a/src/_locales/oc/messages.json +++ b/src/_locales/oc/messages.json @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "message": "Contunhar", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "La pagina blocada vòl redirigir cap a un autre site. Se causissètz de perseguir, aniretz dirèctament a : {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Export to cloud storage", "description": "tooltip" diff --git a/src/_locales/pa/messages.json b/src/_locales/pa/messages.json index b58a1203bc44b..4091c4b2a5c52 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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "ਕਲਾਉਡ ਸਟੋਰੇਜ਼ ਉੱਤੇ ਐਕਸਪੋਰਟ ਕਰੋ", "description": "tooltip" diff --git a/src/_locales/pl/messages.json b/src/_locales/pl/messages.json index a4ce6344d7508..fc0d77b7ff879 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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Powód:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "złośliwa", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "śledząca", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "podejrzana", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Eksportuj do chmury", "description": "tooltip" diff --git a/src/_locales/pt_BR/messages.json b/src/_locales/pt_BR/messages.json index 1704ab211707c..38b3b2c63a08a 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": { @@ -72,11 +72,11 @@ "description": "English: Click: disable/enable uBlock₀ for this site.\n\nCtrl+click: disable uBlock₀ only on this page." }, "popupPowerSwitchInfo1": { - "message": "Clique pra desativar o uBlock₀ neste site.\n\nCtrl+clique pra desativar o uBlock₀ só nesta página.", + "message": "Clique para desativar o uBlock₀ neste site.\n\nCtrl+clique para desativar o uBlock₀ só nesta página.", "description": "Message to be read by screen readers" }, "popupPowerSwitchInfo2": { - "message": "Clique pra ativar o uBlock₀ neste site.", + "message": "Clique para ativar o uBlock₀ neste site.", "description": "Message to be read by screen readers" }, "popupBlockedRequestPrompt": { @@ -116,7 +116,7 @@ "description": "English: Click to open the dashboard" }, "popupTipZapper": { - "message": "Entrar no modo do elemento zapper", + "message": "Entrar no modo de remoção de elementos", "description": "Tooltip for the element-zapper icon in the popup panel" }, "popupTipPicker": { @@ -128,7 +128,7 @@ "description": "Tooltip used for the logger icon in the panel" }, "popupTipReport": { - "message": "Reportar um problema com este site da web", + "message": "Relatar um problema neste site", "description": "Tooltip used for the 'chat' icon in the panel" }, "popupTipNoPopups": { @@ -176,7 +176,7 @@ "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoRemoteFonts2": { - "message": "Clique pra não mais bloquear fontes remotas neste site", + "message": "Clique para deixar de bloquear fontes remotas neste site", "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoScripting1": { @@ -184,7 +184,7 @@ "description": "Tooltip for the no-scripting per-site switch" }, "popupTipNoScripting2": { - "message": "Clique pra não mais desativar o JavaScript neste site", + "message": "Clique para deixar de desativar o JavaScript neste site", "description": "Tooltip for the no-scripting per-site switch" }, "popupNoPopups_v2": { @@ -244,7 +244,7 @@ "description": "" }, "popup3pPassiveRulePrompt": { - "message": "CSS/Imagens de terceiros", + "message": "CSS/imagens de terceiros", "description": "" }, "popupInlineScriptRulePrompt": { @@ -444,7 +444,7 @@ "description": "English: Parse and enforce Adblock+ element hiding filters." }, "3pParseAllABPHideFiltersInfo": { - "message": "Os filtros cosméticos servem pra esconder elementos de uma página da web os quais são considerados um incômodo visual e os quais não podem ser bloqueados pelas engines de filtragem baseadas em requisições de rede.", + "message": "Os filtros cosméticos servem para ocultar elementos em uma página os quais são considerados um incômodo visual e os quais não podem ser bloqueados pelos motores de filtragem baseadas em solicitações de rede.", "description": "Describes the purpose of the 'Parse and enforce cosmetic filters' feature." }, "3pIgnoreGenericCosmeticFilters": { @@ -452,7 +452,7 @@ "description": "This will cause uBO to ignore all generic cosmetic filters." }, "3pIgnoreGenericCosmeticFiltersInfo": { - "message": "Os filtros cosméticos genéricos são aqueles filtros cosméticos os quais são destinados a serem aplicados em todos os sites da web. Ativar esta opção eliminará a sobrecarga da memória e da CPU adicionada as páginas da web como um resultado de lidar com filtros cosméticos genéricos.\n\nÉ recomendado ativar esta opção em dispositivos menos poderosos.", + "message": "Os filtros cosméticos genéricos são aqueles filtros cosméticos os quais são destinados a serem aplicados em todos os sites. Ativar esta opção eliminará a sobrecarga da memória e da CPU adicionada as páginas como um resultado de lidar com filtros cosméticos genéricos.\n\nÉ recomendado ativar esta opção em dispositivos mais lentos.", "description": "Describes the purpose of the 'Ignore generic cosmetic filters' feature." }, "3pSuspendUntilListsAreLoaded": { @@ -536,7 +536,7 @@ "description": "used as a tooltip for error icon beside a list" }, "1pTrustWarning": { - "message": "Não adicionar filtros de fontes não confiáveis.", + "message": "Não adicione filtros de fontes não confiáveis.", "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { @@ -548,7 +548,7 @@ "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { - "message": "Importar e anexar", + "message": "Importar e anexar…", "description": "Button in the 'My filters' pane" }, "1pExport": { @@ -576,7 +576,7 @@ "description": "This will remove all temporary rules" }, "rulesCommit": { - "message": "Submeter", + "message": "Confirmar", "description": "This will persist temporary rules" }, "rulesEdit": { @@ -596,7 +596,7 @@ "description": "" }, "rulesExport": { - "message": "Exportar pro arquivo", + "message": "Exportar para um arquivo…", "description": "Button in the 'My rules' pane" }, "rulesDefaultFileName": { @@ -608,7 +608,7 @@ "description": "English: List of your dynamic filtering rules." }, "rulesFormatHint": { - "message": "Regras da sintaxe: ação do tipo de destino da origem (documentação completa).", + "message": "Regras de sintaxe: origem destino tipo ação (documentação completa).", "description": "English: dynamic rule syntax and full documentation." }, "rulesSort": { @@ -628,7 +628,7 @@ "description": "English: a sort option for list of rules." }, "whitelistPrompt": { - "message": "As diretivas dos sites confiáveis ditam em quais páginas da web o uBlock Origin deve ser desativado. Uma entrada por linha. ", + "message": "As diretivas dos sites confiáveis ditam em quais páginas o uBlock Origin deve ser desativado. Uma entrada por linha. ", "description": "A concise description of the 'Trusted sites' pane." }, "whitelistImport": { @@ -684,7 +684,7 @@ "description": "Tooltip for the DOM inspector button in the logger page" }, "loggerPopupPanelTip": { - "message": "Alternar o painel do pop-up", + "message": "Habilitar o painel pop-up", "description": "Tooltip for the popup panel button in the logger page" }, "loggerInfoTip": { @@ -704,7 +704,7 @@ "description": "Tooltip for the play button in the logger page" }, "loggerRowFiltererButtonTip": { - "message": "Alternar filtragem do coletor", + "message": "Habilitar filtragem do coletor", "description": "Tooltip for the row filterer button in the logger page" }, "logFilterPrompt": { @@ -796,7 +796,7 @@ "description": "Small header to identify the static filtering section" }, "loggerStaticFilteringSentence": { - "message": "{{action}} requisições da rede de {{type}} {{br}}cujo endereço de URL corresponde {{url}} {{br}}e o qual se origina em {{origin}},{{br}}{{importance}} há um filtro de exceção correspondente.", + "message": "{{action}} solicitações de rede do tipo {{type}} {{br}}onde o endereço da URL corresponde a {{url}} {{br}}e que origina de {{origin}},{{br}}{{importance}} há um filtro de exceção correspondente.", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartBlock": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Criar um novo relatório", + "message": "Criar um novo relatório no GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Achar relatórios similares", + "message": "Achar relatórios similares no GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -924,7 +924,7 @@ "description": "First paragraph of 'Questions and support' section in Support pane" }, "supportS3H": { - "message": "Problemas com o filtro/o site da web está quebrado", + "message": "Problemas com filtros/o site não funciona", "description": "Header of 'Filter issues' section in Support pane" }, "supportS3P1": { @@ -932,7 +932,7 @@ "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { - "message": "Importante: Evite usar outros bloqueadores com propósito similar junto do uBlock Origin pois isto pode causar problemas com filtros em sites da web específicos.", + "message": "Importante: Evite usar outros bloqueadores junto com o uBlock Origin pois isto pode causar problemas com filtros em sites específicos.", "description": "Second paragraph of 'Filter issues' section in Support pane" }, "supportS3P3": { @@ -944,7 +944,7 @@ "description": "Header of 'Bug report' section in Support pane" }, "supportS4P1": { - "message": "Reporte problemas com o próprio uBlock Origin no uBlockOrigin/uBlock-issuerastreador de problemas. Requer uma conta no GitHub.", + "message": "Relate problemas com o próprio uBlock Origin no rastreador de problemas do uBlockOrigin/uBlock-issue. Uma conta do GitHub é necessária.", "description": "First paragraph of 'Bug report' section in Support pane" }, "supportS5H": { @@ -956,7 +956,7 @@ "description": "First paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS5P2": { - "message": "Atenção: Informações potencialmente privadas ou sensíveis são eliminadas por padrão. As informações eliminadas podem tornar mais difícil resolver um problema.", + "message": "Importante: Informações potencialmente privadas ou sensíveis são eliminadas por padrão. As informações eliminadas podem dificultar a resolução de um problema.", "description": "Second paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS6H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Pra evitar sobrecarregar os voluntários com relatórios duplicados por favor certifique-se que o problema já não foi reportado.", + "message": "Para evitar sobrecarregar os voluntários com relatórios duplicados por favor verifique se o problema já não foi relatado. Observação: clicar no botão fará com que a origem da página seja enviada ao GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -984,7 +984,7 @@ "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { - "message": "— Escolha uma entrada —", + "message": "— Selecione um tipo —", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { @@ -992,7 +992,7 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "Tem sobreposições ou outros incômodos", + "message": "Tem sobreposições ou outras perturbações", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { @@ -1004,15 +1004,19 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "Funciona mal quando o uBlock Origin está ativado", + "message": "Não funciona direito quando o uBlock Origin está ativado", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { "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\")", + "message": "Rotular a página da web como \"NSFW\" (\"Não é Seguro no Trabalho\")", "description": "A checkbox to use for NSFW sites" }, "supportRedact": { @@ -1056,15 +1060,15 @@ "description": "Shown in the About pane" }, "aboutCDNs": { - "message": "As próprias listas de filtros do uBO estão hospedadas gratuitamente nos seguintes CDNs: ", + "message": "As próprias listas de filtros do uBO estão hospedadas gratuitamente nas seguintes CDNs: ", "description": "Shown in the About pane" }, "aboutCDNsInfo": { - "message": "Um CDN escolhido aleatoriamente é usado quando uma lista de filtros precisa ser atualizada", + "message": "Uma CDN é escolhida automaticamente quando uma lista de filtros precisa ser atualizada.", "description": "Shown in the About pane" }, "aboutBackupDataButton": { - "message": "Fazer backup no arquivo", + "message": "Fazer backup para arquivo", "description": "Text for button to create a backup of all settings" }, "aboutBackupFilename": { @@ -1088,7 +1092,7 @@ "description": "Message to display when an error occurred during restore" }, "aboutResetDataConfirm": { - "message": "Todas as suas configurações serão removidas, e o uBlock₀ reiniciará.\n\nResetar o uBlock₀ para as configurações de fábrica?", + "message": "Todas as suas configurações serão removidas, e o uBlock₀ reiniciará.\n\nRedefinir o uBlock₀ para as configurações de fábrica?", "description": "Message asking user to confirm reset" }, "errorCantConnectTo": { @@ -1187,6 +1191,26 @@ "message": "Prosseguir", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "A página bloqueada deseja redirecionar para outro site. Se você escolher continuar, você navegará diretamente para: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "Motivo:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicioso", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Rastreador", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Má reputação", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exportar pro armazenamento na nuvem", "description": "tooltip" @@ -1232,7 +1256,7 @@ "description": "An entry in the browser's contextual menu" }, "contextMenuSubscribeToList": { - "message": "Subscrever na lista de filtros... ", + "message": "Inscrever-se na lista de filtros...", "description": "An entry in the browser's contextual menu" }, "contextMenuTemporarilyAllowLargeMediaElements": { @@ -1240,7 +1264,7 @@ "description": "A context menu entry, present when large media elements have been blocked on the current site" }, "contextMenuViewSource": { - "message": "Visualizar código fonte…", + "message": "Visualizar código-fonte…", "description": "A context menu entry, to view the source code of the target resource" }, "shortcutCapturePlaceholder": { @@ -1252,7 +1276,7 @@ "description": "Tooltip for the button used to lock scrolling between the views in the 'My rules' pane" }, "genericCopyToClipboard": { - "message": "Copiar pra área de transferência", + "message": "Copiar para a área de transferência", "description": "Label for buttons used to copy something to the clipboard" }, "genericSelectAll": { @@ -1296,7 +1320,7 @@ "description": "Summary of number of errors as reported by the linter " }, "unprocessedRequestTooltip": { - "message": "Não conseguiu filtrar apropriadamente na inicialização do navegador. Recarregue a página pra garantir a filtragem apropriada.", + "message": "Não foi possível filtrar apropriadamente na inicialização do navegador. Recarregue a página para garantir a filtragem apropriada.", "description": "A warning which will appear in the popup panel if needed" }, "dummy": { diff --git a/src/_locales/pt_PT/messages.json b/src/_locales/pt_PT/messages.json index 743b8770b1c0d..bc7b31b803122 100644 --- a/src/_locales/pt_PT/messages.json +++ b/src/_locales/pt_PT/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Finalmente, um bloqueador eficiente. Leve na CPU e memória.", + "message": "Finalmente, um bloqueador eficiente. Leve para a CPU e a memória.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "dashboardName": { @@ -48,7 +48,7 @@ "description": "appears as tab name in dashboard" }, "statsPageName": { - "message": "uBlock₀ — Registador", + "message": "uBlock₀ — Registo", "description": "Title for the logger window" }, "aboutPageName": { @@ -116,7 +116,7 @@ "description": "English: Click to open the dashboard" }, "popupTipZapper": { - "message": "Entrar no modo \"zapper\" de elemento", + "message": "Entrar no modo de remoção rápida de elemento", "description": "Tooltip for the element-zapper icon in the popup panel" }, "popupTipPicker": { @@ -124,7 +124,7 @@ "description": "English: Enter element picker mode" }, "popupTipLog": { - "message": "Abrir o registador", + "message": "Abrir o registo", "description": "Tooltip used for the logger icon in the panel" }, "popupTipReport": { @@ -688,23 +688,23 @@ "description": "Tooltip for the popup panel button in the logger page" }, "loggerInfoTip": { - "message": "uBlock Origin wiki: O registador", + "message": "uBlock Origin wiki: O registo", "description": "Tooltip for the top-right info label in the logger page" }, "loggerClearTip": { - "message": "Limpar registador", + "message": "Limpar registo", "description": "Tooltip for the eraser in the logger page; used to blank the content of the logger" }, "loggerPauseTip": { - "message": "Pausar registador (descartar todos os dados a receber)", + "message": "Pausar registo (descartar todos os dados a receber)", "description": "Tooltip for the pause button in the logger page" }, "loggerUnpauseTip": { - "message": "Retomar registador", + "message": "Retomar registo", "description": "Tooltip for the play button in the logger page" }, "loggerRowFiltererButtonTip": { - "message": "Alternar filtragem do registador", + "message": "Alternar filtragem do registo", "description": "Tooltip for the row filterer button in the logger page" }, "logFilterPrompt": { @@ -712,7 +712,7 @@ "description": "Placeholder string for logger output filtering input field" }, "loggerRowFiltererBuiltinTip": { - "message": "Opções de filtragem do registador", + "message": "Opções de filtragem do registo", "description": "Tooltip for the button to bring up logger output filtering options" }, "loggerRowFiltererBuiltinNot": { @@ -840,7 +840,7 @@ "description": "Message to show when a filter cannot be found in any filter lists" }, "loggerSettingDiscardPrompt": { - "message": "Entradas do registador que não preenchem todas as três condições abaixo serão automaticamente descartadas:", + "message": "Entradas do registo que não preenchem todas as três condições abaixo serão automaticamente descartadas:", "description": "Logger setting: A sentence to describe the purpose of the settings below" }, "loggerSettingPerEntryMaxAge": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Criar novo relatório", + "message": "Criar novo relatório no GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Encontrar relatórios semelhantes", + "message": "Encontrar relatórios semelhantes no GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -936,7 +936,7 @@ "description": "Second paragraph of 'Filter issues' section in Support pane" }, "supportS3P3": { - "message": "Dicas: certifique-se de que as suas listas de filtros estão atualizadas. O registador é a ferramenta principal para diagnosticar problemas relacionados com filtros.", + "message": "Dicas: certifique-se de que as suas listas de filtros estão atualizadas. O registo é a ferramenta principal para diagnosticar problemas relacionados com filtros.", "description": "Third paragraph of 'Filter issues' section in Support pane" }, "supportS4H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Para evitar sobrecarregar os voluntários com relatórios duplicados, por favor verifique se o problema ainda não foi relatado.", + "message": "Para evitar sobrecarregar os voluntários com relatórios duplicados, verifique se o problema ainda não foi relatado. Nota: clicar no botão fará com que a origem da página seja enviada para o GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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" @@ -1132,7 +1136,7 @@ "description": "Firefox/Fennec-specific: Show Dashboard" }, "showNetworkLogButton": { - "message": "Mostrar registador", + "message": "Mostrar registo", "description": "Firefox/Fennec-specific: Show Logger" }, "fennecMenuItemBlockingOff": { @@ -1187,6 +1191,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exportar para a nuvem", "description": "tooltip" diff --git a/src/_locales/ro/messages.json b/src/_locales/ro/messages.json index 3881e7821a45a..847b522b7db97 100644 --- a/src/_locales/ro/messages.json +++ b/src/_locales/ro/messages.json @@ -488,7 +488,7 @@ "description": "Filter lists section name" }, "3pGroupCookies": { - "message": "Cookie notices", + "message": "Notificări privind cookie-urile", "description": "Filter lists section name" }, "3pGroupAnnoyances": { @@ -540,11 +540,11 @@ "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { - "message": "Enable my custom filters", + "message": "Activați filtrele mele personalizate", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { - "message": "Allow custom filters requiring trust", + "message": "Permiteți filtre personalizate care necesită încredere", "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { @@ -624,7 +624,7 @@ "description": "English: a sort option for list of rules." }, "rulesSortByDestination": { - "message": "Destinaţia", + "message": "Destinație", "description": "English: a sort option for list of rules." }, "whitelistPrompt": { @@ -840,7 +840,7 @@ "description": "Message to show when a filter cannot be found in any filter lists" }, "loggerSettingDiscardPrompt": { - "message": "Intrările din jurnal care nu îndeplinesc cele trei condiții de mai jos vor fi respinse automat:", + "message": "Intrările în registrul de logare care nu îndeplinesc toate cele trei condiții de mai jos vor fi automat eliminate.", "description": "Logger setting: A sentence to describe the purpose of the settings below" }, "loggerSettingPerEntryMaxAge": { @@ -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": "Duce la programe dăunătoare, 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,26 @@ "message": "Continuă", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Pagina blocată dorește să redirecționeze către un alt site. Dacă alegeți să continuați, veți naviga direct către: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exportă către stocarea în cloud", "description": "tooltip" diff --git a/src/_locales/ru/messages.json b/src/_locales/ru/messages.json index 2d535dd32f159..16561e3393a46 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": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Создать новый отчет", + "message": "Создать новый отчёт в GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Найти похожие отчеты", + "message": "Найти похожие отчёты в GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Чтобы не обременять волонтеров дублированными отчетами, пожалуйста, убедитесь, что о данной проблеме еще не сообщали", + "message": "Чтобы не обременять добровольцев повторяющимися отчётами, пожалуйста, убедитесь, что об этой проблеме ещё не сообщали. Примечание: щелчок по кнопке приведёт к отправке адреса посещенной страницы GitHub'у.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "message": "Продолжить", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Заблокированная страница собирается перенаправить вас на другой сайт. Если вы решите продолжить, вы перейдете непосредственно на: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "Причина:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Вредоносная активность", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Трекер", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Сомнительное содержание", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Экспорт в облачное хранилище", "description": "tooltip" diff --git a/src/_locales/si/messages.json b/src/_locales/si/messages.json index afd9c19d6f97f..0b9219d1da867 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": { @@ -48,31 +48,31 @@ "description": "appears as tab name in dashboard" }, "statsPageName": { - "message": "uBlock₀ — Logger", + "message": "යූබ්ලොක්₀ — ලඝුර", "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": { - "message": "uBlock₀ — Asset viewer", + "message": "යූබ්ලොක්₀ — වත්කම් දක්වනය", "description": "Title for the asset viewer page" }, "advancedSettingsPageName": { - "message": "වැඩිදුර සැකසුම්", + "message": "සංකීර්ණ සැකසුම්", "description": "Title for the advanced settings page" }, "popupPowerSwitchInfo": { - "message": "Click: disable/enable uBlock₀ for this site.\n\nCtrl+click: disable uBlock₀ only on this page.", + "message": "ඔබන්න: මෙම අඩවියට යූබ්ලොක්₀ අබල/සබල කරන්න.\n\nCtrl+ඔබන්න: මෙම පිටුවට පමණක් යූබ්ලොක්₀ අබල කරන්න.", "description": "English: Click: disable/enable uBlock₀ for this site.\n\nCtrl+click: disable uBlock₀ only on this page." }, "popupPowerSwitchInfo1": { - "message": "Click to disable uBlock₀ for this site.\n\nCtrl+click to disable uBlock₀ only on this page.", + "message": "මෙම අඩවියට යූබ්ලොක්₀ අබල/සබල කිරීමට ඔබන්න.\n\nමෙම පිටුවට පමණක් යූබ්ලොක්₀ අබල කිරීමට Ctrl+ඔබන්න.", "description": "Message to be read by screen readers" }, "popupPowerSwitchInfo2": { @@ -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,99 +112,99 @@ "description": "For the new mobile-friendly popup design" }, "popupTipDashboard": { - "message": "උපකරණපුවරුව විවෘත කරන්න", + "message": "උපකරණ පුවරුව අරින්න", "description": "English: Click to open the dashboard" }, "popupTipZapper": { - "message": "Enter element zapper mode", + "message": "මූලද්‍රව්‍ය zapper ප්‍රකාරයට ඇතුළු වන්න", "description": "Tooltip for the element-zapper icon in the popup panel" }, "popupTipPicker": { - "message": "Enter element picker mode", + "message": "මූලද්‍රව්‍ය තෝරක ප්‍රකාරයට ඇතුළු වන්න", "description": "English: Enter element picker mode" }, "popupTipLog": { - "message": "Open the logger", + "message": "ලඝුර අරින්න", "description": "Tooltip used for the logger icon in the panel" }, "popupTipReport": { - "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": { - "message": "Click to block all popups on this site", + "message": "මෙම අඩවියේ ඇති සියලුම උත්පතන අවහිර කිරීමට ක්ලික් කරන්න.", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoPopups2": { - "message": "Click to no longer block all popups on this site", + "message": "මෙම අඩවියේ ඇති සියලුම උත්පතන තවදුරටත් අවහිර නොකිරීමට ක්ලික් කරන්න.", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoLargeMedia": { - "message": "Toggle the blocking of large media elements for this site", + "message": "මෙම අඩවිය සඳහා විශාල මාධ්‍ය අංග අවහිර කිරීම ටොගල් කරන්න.", "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoLargeMedia1": { - "message": "Click to block large media elements on this site", + "message": "මෙම අඩවියේ විශාල මාධ්‍ය අංග අවහිර කිරීමට ක්ලික් කරන්න.", "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoLargeMedia2": { - "message": "Click to no longer block large media elements on this site", + "message": "මෙම අඩවියේ විශාල මාධ්‍ය අංග තවදුරටත් අවහිර නොකිරීමට ක්ලික් කරන්න.", "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoCosmeticFiltering": { - "message": "Toggle cosmetic filtering for this site", + "message": "මෙම අඩවිය සඳහා රූපලාවන්‍ය පෙරහන ටොගල් කරන්න", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoCosmeticFiltering1": { - "message": "Click to disable cosmetic filtering on this site", + "message": "මෙම අඩවියේ රූපලාවන්‍ය පෙරහන් අක්‍රිය කිරීමට ක්ලික් කරන්න.", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoCosmeticFiltering2": { - "message": "Click to enable cosmetic filtering on this site", + "message": "මෙම අඩවියේ රූපලාවන්‍ය පෙරහන් සක්‍රීය කිරීමට ක්ලික් කරන්න.", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoRemoteFonts": { - "message": "Toggle the blocking of remote fonts for this site", + "message": "මෙම අඩවිය සඳහා දුරස්ථ අකුරු අවහිර කිරීම ටොගල් කරන්න", "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoRemoteFonts1": { - "message": "Click to block remote fonts on this site", + "message": "මෙම අඩවියේ දුරස්ථ අකුරු අවහිර කිරීමට ක්ලික් කරන්න.", "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoRemoteFonts2": { - "message": "Click to no longer block remote fonts on this site", + "message": "මෙම අඩවියේ දුරස්ථ අකුරු තවදුරටත් අවහිර නොකිරීමට ක්ලික් කරන්න.", "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoScripting1": { - "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": { - "message": "Cosmetic filtering", + "message": "රූපලාවන්‍ය පෙරහන", "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": { @@ -220,15 +220,15 @@ "description": "Tooltip when hovering the top-most cell of the global-rules column." }, "popupTipLocalRules": { - "message": "Local rules: this column is for rules which apply to the current site only.\nLocal rules override global rules.", + "message": "දේශීය නීති: මෙම තීරුව වත්මන් අඩවියට පමණක් අදාළ වන නීති සඳහා වේ.\nදේශීය නීති ගෝලීය නීති අභිබවා යයි.", "description": "Tooltip when hovering the top-most cell of the local-rules column." }, "popupTipSaveRules": { - "message": "Click to make your changes permanent.", + "message": "ඔබගේ වෙනස්කම් ස්ථිර කිරීමට ක්ලික් කරන්න.", "description": "Tooltip when hovering over the padlock in the dynamic filtering pane." }, "popupTipRevertRules": { - "message": "Click to revert your changes.", + "message": "ඔබගේ වෙනස්කම් ප්‍රතිවර්තනය කිරීමට ක්ලික් කරන්න.", "description": "Tooltip when hovering over the eraser in the dynamic filtering pane." }, "popupAnyRulePrompt": { @@ -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": { @@ -268,7 +268,7 @@ "description": "appears in popup" }, "popupHitDomainCount": { - "message": "{{count}} out of {{total}}", + "message": "{{total}}න් {{count}}", "description": "appears in popup" }, "popupVersion": { @@ -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": { @@ -288,7 +288,7 @@ "description": "English: Create" }, "pickerPick": { - "message": "Pick", + "message": "තෝරන්න", "description": "English: Pick" }, "pickerQuit": { @@ -304,31 +304,31 @@ "description": "English: header for a type of filter in the element picker dialog" }, "pickerCosmeticFilters": { - "message": "Cosmetic filters", + "message": "රූපලාවන්‍ය පෙරහන්", "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": { - "message": "Hide placeholders of blocked elements", + "message": "අවහිර කළ මූලද්‍රව්‍යවල ස්ථාන දරන්නන් සඟවන්න", "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": { - "message": "Disable tooltips", + "message": "මෙවලම් ඉඟි අක්‍රීය කරන්න", "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": { @@ -352,115 +352,115 @@ "description": "" }, "settingsAdvancedUserPrompt": { - "message": "I am an advanced user", + "message": "මම ප්‍රගත පරිශ්‍රීලකයෙකි", "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": "දේශීය IP ලිපින කාන්දු වීම WebRTC වලක්වන්න", "description": "English: " }, "settingPerSiteSwitchGroup": { - "message": "Default behavior", + "message": "පෙරනිමි හැසිරීම", "description": "" }, "settingPerSiteSwitchGroupSynopsis": { - "message": "These default behaviors can be overridden on a per-site basis", + "message": "මෙම පෙරනිමි හැසිරීම් එක් එක් අඩවියට අනුව අභිබවා යා හැක.", "description": "" }, "settingsNoCosmeticFilteringPrompt": { - "message": "Disable cosmetic filtering", + "message": "රූපලාවන්‍ය පෙරහන අක්‍රීය කරන්න", "description": "" }, "settingsNoLargeMediaPrompt": { - "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": { - "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": { - "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": { - "message": "{{netFilterCount}} network filters + {{cosmeticFilterCount}} cosmetic filters from:", + "message": "{{netFilterCount}} ජාල පෙරහන් + {{cosmeticFilterCount}} රූපලාවන්‍ය පෙරහන්:", "description": "Appears at the top of the _3rd-party filters_ pane" }, "3pListsOfBlockedHostsPerListStats": { - "message": "{{used}} used out of {{total}}", + "message": "{{total}} න් {{used}} ක් භාවිතා කර ඇත", "description": "Appears aside each filter list in the _3rd-party filters_ pane" }, "3pAutoUpdatePrompt1": { - "message": "Auto-update filter lists", + "message": "පෙරහන් ලැයිස්තු ස්වයංක්‍රීයව යාවත්කාලීන කරන්න", "description": "A checkbox in the _3rd-party filters_ pane" }, "3pUpdateNow": { - "message": "දැන් යාවත්කාල කරන්න", + "message": "යාවත්කාල කරන්න", "description": "A button in the in the _3rd-party filters_ pane" }, "3pPurgeAll": { - "message": "Purge all caches", + "message": "සියලුම හැඹිලි ඉවත් කරන්න", "description": "A button in the in the _3rd-party filters_ pane" }, "3pParseAllABPHideFiltersPrompt1": { - "message": "Parse and enforce cosmetic filters", + "message": "රූපලාවන්‍ය පෙරහන් විග්‍රහ කර බලාත්මක කරන්න", "description": "English: Parse and enforce Adblock+ element hiding filters." }, "3pParseAllABPHideFiltersInfo": { - "message": "Cosmetic filters serve to hide elements in a web page which are deemed to be a visual nuisance, and which can't be blocked by the network request-based filtering engines.", + "message": "රූපලාවන්‍ය පෙරහන් යනු වෙබ් පිටුවක දෘශ්‍ය කරදරයක් ලෙස සලකනු ලබන සහ ජාල ඉල්ලීම් මත පදනම් වූ පෙරහන් එන්ජින් මගින් අවහිර කළ නොහැකි අංග සැඟවීමට සේවය කරයි.", "description": "Describes the purpose of the 'Parse and enforce cosmetic filters' feature." }, "3pIgnoreGenericCosmeticFilters": { - "message": "Ignore generic cosmetic filters", + "message": "සාමාන්‍ය රූපලාවන්‍ය පෙරහන් නොසලකා හරින්න.", "description": "This will cause uBO to ignore all generic cosmetic filters." }, "3pIgnoreGenericCosmeticFiltersInfo": { - "message": "Generic cosmetic filters are those cosmetic filters which are meant to apply on all web sites. Enabling this option will eliminate the memory and CPU overhead added to web pages as a result of handling generic cosmetic filters.\n\nIt is recommended to enable this option on less powerful devices.", + "message": "සාමාන්‍ය රූපලාවන්‍ය පෙරහන් යනු සියලුම වෙබ් අඩවිවල යෙදීමට අදහස් කරන රූපලාවන්‍ය පෙරහන් වේ. මෙම විකල්පය සක්‍රීය කිරීමෙන් සාමාන්‍ය රූපලාවන්‍ය පෙරහන් හැසිරවීමේ ප්‍රතිඵලයක් ලෙස වෙබ් පිටුවලට එකතු වන මතකය සහ CPU උඩිස් බර ඉවත් කරනු ඇත.\n\nඅඩු බලවත් උපාංගවල මෙම විකල්පය සක්‍රීය කිරීම නිර්දේශ කෙරේ.", "description": "Describes the purpose of the 'Ignore generic cosmetic filters' feature." }, "3pSuspendUntilListsAreLoaded": { - "message": "Suspend network activity until all filter lists are loaded", + "message": "සියලුම පෙරහන් ලැයිස්තු පූරණය වන තුරු ජාල ක්‍රියාකාරකම් අත්හිටුවන්න.", "description": "A checkbox in the 'Filter lists' pane" }, "3pListsOfBlockedHostsHeader": { - "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,31 +476,31 @@ "description": "Filter lists section name" }, "3pGroupPrivacy": { - "message": "පෞද්ගලිකත්වය", + "message": "පෞද්ගලිකත්‍වය", "description": "Filter lists section name" }, "3pGroupMalware": { - "message": "Malware protection, security", + "message": "අනිෂ්ට මෘදුකාංග ආරක්ෂාව, ආරක්ෂාව", "description": "Filter lists section name" }, "3pGroupSocial": { - "message": "Social widgets", + "message": "සමාජ විජට්", "description": "Filter lists section name" }, "3pGroupCookies": { - "message": "Cookie notices", + "message": "දත්තකඩ දැන්වීම්", "description": "Filter lists section name" }, "3pGroupAnnoyances": { - "message": "Annoyances", + "message": "කරදර", "description": "Filter lists section name" }, "3pGroupMultipurpose": { - "message": "Multipurpose", + "message": "බහුකාර්ය", "description": "Filter lists section name" }, "3pGroupRegions": { - "message": "Regions, languages", + "message": "කලාප, භාෂා", "description": "Filter lists section name" }, "3pGroupCustom": { @@ -508,23 +508,23 @@ "description": "Filter lists section name" }, "3pImport": { - "message": "ඇතුල් කරන්න...", + "message": "ආයාත කරන්න...", "description": "The label for the checkbox used to import external filter lists" }, "3pExternalListsHint": { - "message": "One URL per line. Invalid URLs will be silently ignored.", + "message": "පේළියකට එක් URL එකක් බැගින්. අවලංගු URL නිහඬව නොසලකා හරිනු ලැබේ.", "description": "Short information about how to use the textarea to import external filter lists by URL" }, "3pExternalListObsolete": { - "message": "Out of date.", + "message": "කල් ඉකුත් වී ඇත.", "description": "used as a tooltip for the out-of-date icon beside a list" }, "3pViewContent": { - "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,31 +532,31 @@ "description": "used as a tooltip for the spinner icon beside a list" }, "3pNetworkError": { - "message": "A network error prevented the resource from being updated.", + "message": "ජාල දෝෂයක් නිසා සම්පත යාවත්කාලීන වීම වැළැක්විණි.", "description": "used as a tooltip for error icon beside a list" }, "1pTrustWarning": { - "message": "Do not add filters from untrusted sources.", + "message": "විශ්වාස නොකළ මූලාශ්‍රවලින් පෙරහන් එක් නොකරන්න.", "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { - "message": "Enable my custom filters", + "message": "මගේ අභිරුචි පෙරහන් සක්‍රීය කරන්න", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { - "message": "Allow custom filters requiring trust", + "message": "විශ්වාසය අවශ්‍ය අභිරුචි පෙරහන් වලට ඉඩ දෙන්න.", "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { - "message": "Import and append…", + "message": "…ආයාත කර එකතු කරන්න", "description": "Button in the 'My filters' pane" }, "1pExport": { - "message": "නිර්යාත", + "message": "නිර්යාත කරන්න...", "description": "Button in the 'My filters' pane" }, "1pExportFilename": { - "message": "my-ublock-static-filters_{{datetime}}.txt", + "message": "මගේ-ublock-static-filters_{{datetime}}.txt", "description": "English: my-ublock-static-filters_{{datetime}}.txt" }, "1pApplyChanges": { @@ -564,7 +564,7 @@ "description": "English: Apply changes" }, "rulesPermanentHeader": { - "message": "Permanent rules", + "message": "ස්ථිර නීති", "description": "header" }, "rulesTemporaryHeader": { @@ -572,11 +572,11 @@ "description": "header" }, "rulesRevert": { - "message": "Revert", + "message": "ප්‍රතිවර්තනය", "description": "This will remove all temporary rules" }, "rulesCommit": { - "message": "Commit", + "message": "කැප කරන්න", "description": "This will persist temporary rules" }, "rulesEdit": { @@ -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,19 +600,19 @@ "description": "Button in the 'My rules' pane" }, "rulesDefaultFileName": { - "message": "මගේ-ස්ථිර-නීති_{{datetime}}.txt", + "message": "මාගේ-ublock-ගතික-නීති_{{datetime}}.txt", "description": "default file name to use" }, "rulesHint": { - "message": "List of your dynamic filtering rules.", + "message": "ඔබගේ ගතික පෙරහන් නීති ලැයිස්තුව.", "description": "English: List of your dynamic filtering rules." }, "rulesFormatHint": { - "message": "Rule syntax: source destination type action (full documentation).", + "message": "රීති වාක්‍ය ඛණ්ඩය: මූලාශ්‍ර ගමනාන්ත වර්ගය ක්‍රියාව (සම්පූර්ණ ලියකියවිලි).", "description": "English: dynamic rule syntax and full documentation." }, "rulesSort": { - "message": "Sort:", + "message": "වර්ගනය:", "description": "English: label for sort option." }, "rulesSortByType": { @@ -620,27 +620,27 @@ "description": "English: a sort option for list of rules." }, "rulesSortBySource": { - "message": "Source", + "message": "මූලාශ්‍රය", "description": "English: a sort option for list of rules." }, "rulesSortByDestination": { - "message": "Destination", + "message": "ගමනාන්තය", "description": "English: a sort option for list of rules." }, "whitelistPrompt": { - "message": "The trusted site directives dictate on which web pages uBlock Origin should be disabled. One entry per line.", + "message": "විශ්වාසදායක අඩවි නියෝග මඟින් uBlock Origin අක්‍රිය කළ යුත්තේ කුමන වෙබ් පිටු මතද යන්න නියම කරයි. පේළියකට එක් ඇතුළත් කිරීමක් පමණි.", "description": "A concise description of the 'Trusted sites' pane." }, "whitelistImport": { - "message": "Import and append…", + "message": "…ආයාත කර එකතු කරන්න", "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { - "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": { @@ -668,55 +668,55 @@ "description": "Appears in the logger's tab selector" }, "logBehindTheScene": { - "message": "Tabless", + "message": "මේස", "description": "Pretty name for behind-the-scene network requests" }, "loggerCurrentTab": { - "message": "Current tab", + "message": "වත්මන් ටැබය", "description": "Appears in the logger's tab selector" }, "loggerReloadTip": { - "message": "Reload the tab content", + "message": "ටැබ් අන්තර්ගතය නැවත පූරණය කරන්න", "description": "Tooltip for the reload button in the logger page" }, "loggerDomInspectorTip": { - "message": "Toggle the DOM inspector", + "message": "DOM පරීක්ෂක ටොගල් කරන්න", "description": "Tooltip for the DOM inspector button in the logger page" }, "loggerPopupPanelTip": { - "message": "Toggle the popup panel", + "message": "උත්පතන පැනලය ටොගල් කරන්න", "description": "Tooltip for the popup panel button in the logger page" }, "loggerInfoTip": { - "message": "uBlock Origin wiki: The logger", + "message": "uBlock සම්භවය විකි: ලොගර්", "description": "Tooltip for the top-right info label in the logger page" }, "loggerClearTip": { - "message": "Clear logger", + "message": "ලොගර් හිස් කරන්න", "description": "Tooltip for the eraser in the logger page; used to blank the content of the logger" }, "loggerPauseTip": { - "message": "Pause logger (discard all incoming data)", + "message": "ලොගර් විරාම කරන්න (එන සියලුම දත්ත ඉවතලන්න)", "description": "Tooltip for the pause button in the logger page" }, "loggerUnpauseTip": { - "message": "Unpause logger", + "message": "ලොගර් විරාම නොකරන්න", "description": "Tooltip for the play button in the logger page" }, "loggerRowFiltererButtonTip": { - "message": "Toggle logger filtering", + "message": "ලොගර් පෙරහන ටොගල් කරන්න", "description": "Tooltip for the row filterer button in the logger page" }, "logFilterPrompt": { - "message": "filter logger content", + "message": "පෙරහන් ලොගර් අන්තර්ගතය", "description": "Placeholder string for logger output filtering input field" }, "loggerRowFiltererBuiltinTip": { - "message": "Logger filtering options", + "message": "ලොගර් පෙරහන් විකල්ප", "description": "Tooltip for the button to bring up logger output filtering options" }, "loggerRowFiltererBuiltinNot": { - "message": "Not", + "message": "නැහැ", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltinEventful": { @@ -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,15 +760,15 @@ "description": "Label to identify a rule field" }, "loggerEntryDetailsContext": { - "message": "Context", + "message": "සන්දර්භය", "description": "Label to identify a context field (typically a hostname)" }, "loggerEntryDetailsRootContext": { - "message": "Root context", + "message": "මූල සන්දර්භය", "description": "Label to identify a root context field (typically a hostname)" }, "loggerEntryDetailsPartyness": { - "message": "Partyness", + "message": "සාද ගතිය", "description": "Label to identify a field providing partyness information" }, "loggerEntryDetailsType": { @@ -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,11 +792,11 @@ "description": "Label for the type selector" }, "loggerStaticFilteringHeader": { - "message": "Static filter", + "message": "ස්ථිතික පෙරහන", "description": "Small header to identify the static filtering section" }, "loggerStaticFilteringSentence": { - "message": "{{action}} network requests of {{type}} {{br}}which URL address matches {{url}} {{br}}and which originates {{origin}},{{br}}{{importance}} there is a matching exception filter.", + "message": "{{action}} ජාල ඉල්ලීම් {{type}} {{br}}වන URL ලිපිනය {{url}} {{br}}ට ගැලපෙන අතර {{origin}}ට ආරම්භ වේ,{{br}}{{importance}} ට ගැලපෙන ව්‍යතිරේක පෙරහනක් ඇත.", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartBlock": { @@ -804,7 +804,7 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartAllow": { - "message": "ඉඩදෙන්න", + "message": "ඉඩ දෙන්න", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartType": { @@ -816,47 +816,47 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartOrigin": { - "message": "from “{{origin}}”", + "message": "“{{origin}}” වෙතින්", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartAnyOrigin": { - "message": "from anywhere", + "message": "ඕනෑම තැනක සිට", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartNotImportant": { - "message": "except when", + "message": "විට හැර", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartImportant": { - "message": "even if", + "message": "විට දී වුවත්", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringFinderSentence1": { - "message": "Static filter {{filter}} found in:", + "message": "ස්ථිතික පෙරහන {{filter}} හමු වූයේ:", "description": "Below this sentence, the filter list(s) in which the filter was found" }, "loggerStaticFilteringFinderSentence2": { - "message": "Static filter could not be found in any of the currently enabled filter lists", + "message": "දැනට සක්‍රිය කර ඇති කිසිදු පෙරහන් ලැයිස්තුවක ස්ථිතික පෙරහන සොයාගත නොහැකි විය.", "description": "Message to show when a filter cannot be found in any filter lists" }, "loggerSettingDiscardPrompt": { - "message": "Logger entries which do not fulfill all three conditions below will be automatically discarded:", + "message": "පහත කොන්දේසි තුනම සපුරා නොමැති ලොගර් ඇතුළත් කිරීම් ස්වයංක්‍රීයව ඉවත දමනු ලැබේ:", "description": "Logger setting: A sentence to describe the purpose of the settings below" }, "loggerSettingPerEntryMaxAge": { - "message": "Preserve entries from the last {{input}} minutes", + "message": "අවසාන මිනිත්තු {{input}} වලින් ඇතුළත් කිරීම් සුරකින්න", "description": "A logger setting" }, "loggerSettingPerTabMaxLoads": { - "message": "Preserve at most {{input}} page loads per tab", + "message": "ටැබ් එකකට උපරිම වශයෙන් {{input}} පිටු පූරණ සංරක්ෂණය කරන්න", "description": "A logger setting" }, "loggerSettingPerTabMaxEntries": { - "message": "Preserve at most {{input}} entries per tab", + "message": "ටැබ් එකකට උපරිම වශයෙන් {{input}} ඇතුළත් කිරීම් සංරක්ෂණය කරන්න", "description": "A logger setting" }, "loggerSettingPerEntryLineCount": { - "message": "Use {{input}} lines per entry in vertically expanded mode", + "message": "සිරස් අතට පුළුල් කළ ප්‍රකාරයේදී ඇතුළත් කිරීමකට {{input}} රේඛා භාවිතා කරන්න.", "description": "A logger setting" }, "loggerSettingHideColumnsPrompt": { @@ -872,15 +872,15 @@ "description": "A label for the filter or rule column" }, "loggerSettingHideColumnContext": { - "message": "{{input}} Context", + "message": "{{input}} සන්දර්භය", "description": "A label for the context column" }, "loggerSettingHideColumnPartyness": { - "message": "{{input}} Partyness", + "message": "{{input}} සාද ස්වභාවය", "description": "A label for the partyness column" }, "loggerExportFormatList": { - "message": "List", + "message": "ලැයිස්තුව", "description": "Label for radio-button to pick export format" }, "loggerExportFormatTable": { @@ -888,131 +888,135 @@ "description": "Label for radio-button to pick export format" }, "loggerExportEncodePlain": { - "message": "Plain", + "message": "සරල", "description": "Label for radio-button to pick export text format" }, "loggerExportEncodeMarkdown": { - "message": "Markdown", + "message": "මාර්ක්ඩවුන්", "description": "Label for radio-button to pick export text format" }, "supportOpenButton": { - "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 Origin හි සියලුම විශේෂාංග ගැන ඉගෙන ගැනීමට uBlock/wiki හි ඇති ලේඛන කියවන්න.", "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": "ප්‍රශ්නවලට පිළිතුරු සහ අනෙකුත් ආකාරයේ උපකාර සහාය /r/uBlockOriginයන උප රෙඩිට් එකෙන් සපයනු ලැබේ.", "description": "First paragraph of 'Questions and support' section in Support pane" }, "supportS3H": { - "message": "Filter issues/website is broken", + "message": "පෙරහන් ගැටළු/වෙබ් අඩවිය බිඳ වැටී ඇත", "description": "Header of 'Filter issues' section in Support pane" }, "supportS3P1": { - "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", + "message": "නිශ්චිත වෙබ් අඩවි සමඟ පෙරහන් ගැටළු uBlockOrigin/uAssets ගැටළු ට්රැකර්වෙත වාර්තා කරන්න. GitHub ගිණුමක් අවශ්‍යයි.", "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { - "message": "Important: Avoid using other similarly-purposed blockers along with uBlock Origin, as this may cause filter issues on specific websites.", + "message": "වැදගත්: uBlock Origin සමඟ සමාන අරමුණු සහිත වෙනත් අවහිර කරන්නන් භාවිතා කිරීමෙන් වළකින්න, මන්ද මෙය නිශ්චිත වෙබ් අඩවි වල පෙරහන් ගැටළු ඇති කළ හැකිය.", "description": "Second paragraph of 'Filter issues' section in Support pane" }, "supportS3P3": { - "message": "Tips: Be sure your filter lists are up to date. The logger is the primary tool to diagnose filter-related issues.", + "message": "ඉඟි: ඔබගේ පෙරහන් ලැයිස්තු යාවත්කාලීනව ඇති බවට වග බලා ගන්න. පෙරහන් ආශ්‍රිත ගැටළු හඳුනා ගැනීම සඳහා ලොගර් මූලික මෙවලම වේ.", "description": "Third paragraph of 'Filter issues' section in Support pane" }, "supportS4H": { - "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 ගැටළු ට්‍රැකර්වෙත වාර්තා කරන්න. GitHub ගිණුමක් අවශ්‍යයි.", "description": "First paragraph of 'Bug report' section in Support pane" }, "supportS5H": { - "message": "Troubleshooting Information", + "message": "දෝශ නිරාකරණ තොරතුරු", "description": "Header of 'Troubleshooting Information' section in Support pane" }, "supportS5P1": { - "message": "Below is technical information that might be useful when volunteers are trying to help you solve a problem.", + "message": "ස්වේච්ඡා සේවකයන් ගැටලුවක් විසඳීමට ඔබට උදව් කිරීමට උත්සාහ කරන විට ප්‍රයෝජනවත් විය හැකි තාක්ෂණික තොරතුරු පහත දැක්වේ.", "description": "First paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS5P2": { - "message": "Important: Potentially private or sensitive information is redacted by default. Redacted information may make it more difficult to solve a problem.", + "message": "වැදගත්: පුද්ගලික හෝ සංවේදී තොරතුරු පෙරනිමියෙන් සංස්කරණය කරනු ලැබේ. සංස්කරණය කරන ලද තොරතුරු ගැටළුවක් විසඳීම වඩාත් අපහසු කළ හැකිය.", "description": "Second paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS6H": { - "message": "Report a filter issue", + "message": "පෙරහන් ගැටළුවක් වාර්තා කරන්න", "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "අනුපිටපත් වාර්තා සමඟ ස්වේච්ඡා සේවකයින්ට බරක් වීම වළක්වා ගැනීම සඳහා, කරුණාකර ගැටළුව දැනටමත් වාර්තා කර නොමැති බව තහවුරු කරගන්න. සටහන: බොත්තම ක්ලික් කිරීමෙන් පිටුවේ මූලාරම්භය GitHub වෙත යවනු ලැබේ.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { - "message": "Filter lists are updated daily. Be sure your issue has not already been addressed in the most recent filter lists.", + "message": "පෙරහන් ලැයිස්තු දිනපතා යාවත්කාලීන වේ. ඔබගේ ගැටලුව මෑත කාලීන පෙරහන් ලැයිස්තු වල දැනටමත් විසඳා නොමැති බවට වග බලා ගන්න.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S2": { - "message": "Verify that the issue still exists after reloading the problematic webpage.", + "message": "ගැටළු සහගත වෙබ් පිටුව නැවත පූරණය කිරීමෙන් පසුවද ගැටලුව පවතින බව තහවුරු කරන්න.", "description": "A paragraph in the filter issue reporter section" }, "supportS6URL": { - "message": "Address of the web page:", + "message": "වියමන පිටුවේ ලිපිනය:", "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "The web page…", + "message": "වියමන පිටුව…", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { - "message": "-- Pick an entry --", + "message": "-- නිවේශිතයක් තෝරන්න --", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { - "message": "Shows ads or ad leftovers", + "message": "දැන්වීම් හෝ දැන්වීම් ඉතිරි කොටස් පෙන්වයි", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "Has overlays or other nuisances", + "message": "උඩැතිරි හෝ වෙනත් කරදර ඇති", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { - "message": "Detects uBlock Origin", + "message": "යූබ්ලොක් ඔරිජින් හඳුනා ගනියි", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { - "message": "Has privacy-related issues", + "message": "පෞද්ගලිකත්‍වය ආශ්‍රිත ගැටළු තිබේ", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "Malfunctions when uBlock Origin is enabled", + "message": "uBlock Origin සක්‍රීය කර ඇති විට සිදුවන අක්‍රමිකතා", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { - "message": "Opens unwanted tabs or windows", + "message": "අනවශ්‍ය පටිති හෝ කවුළු අරියි", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "නරක මෘදුකාංග, තතුබෑම් වලට මග පාදයි", "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": { @@ -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,19 +1052,19 @@ "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" }, "aboutCDNs": { - "message": "uBO's own filter lists are freely hosted on the following CDNs:", + "message": "uBO හි පෙරහන් ලැයිස්තු පහත CDNsමත නිදහසේ සත්කාරකත්වය දරයි:", "description": "Shown in the About pane" }, "aboutCDNsInfo": { - "message": "A randomly picked CDN is used when a filter list needs to be updated.", + "message": "පෙරහන් ලැයිස්තුවක් යාවත්කාලීන කිරීමට අවශ්‍ය වූ විට අහඹු ලෙස තෝරාගත් CDN එකක් භාවිතා වේ.", "description": "Shown in the About pane" }, "aboutBackupDataButton": { @@ -1068,27 +1072,27 @@ "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": { - "message": "ගොනුවකින් ප්‍රත්‍යර්පණය කරන්න...", + "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\nuBlock₀ කර්මාන්තශාලා සැකසුම් වෙත නැවත සකසන්නද?", "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": { @@ -1120,7 +1124,7 @@ "description": "English: {{value}} hours ago" }, "elapsedOneDayAgo": { - "message": "දිනකට පෙර", + "message": "දවසකට පෙර", "description": "English: a day ago" }, "elapsedManyDaysAgo": { @@ -1132,31 +1136,31 @@ "description": "Firefox/Fennec-specific: Show Dashboard" }, "showNetworkLogButton": { - "message": "Show Logger", + "message": "ලඝුව පෙන්වන්න", "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": { - "message": "uBlock Origin has prevented the following page from loading:", + "message": "uBlock Origin විසින් පහත පිටුව පූරණය වීම වළක්වා ඇත:", "description": "Used in the strict-blocking page" }, "docblockedPrompt2": { - "message": "Because of the following filter:", + "message": "පහත පෙරහන නිසා:", "description": "Used in the strict-blocking page" }, "docblockedNoParamsPrompt": { - "message": "without parameters", + "message": "පරාමිතීන් නොමැතිව", "description": "label to be used for the parameter-less URL: https://cloud.githubusercontent.com/assets/585534/9832014/bfb1b8f0-593b-11e5-8a27-fba472a5529a.png" }, "docblockedFoundIn": { - "message": "Found in:", + "message": "මෙහි හමු විය:", "description": "English: List of filter list names follows" }, "docblockedBack": { @@ -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": { @@ -1180,13 +1184,33 @@ "description": "English: Temporarily" }, "docblockedDisablePermanent": { - "message": "සදාකාලිකව", + "message": "සදහටම", "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "මේඝ ආචයනයට නිර්යාත කරන්න", "description": "tooltip" @@ -1196,7 +1220,7 @@ "description": "tooltip" }, "cloudPullAndMerge": { - "message": "මේඝ ආචයනයෙන් ආයාත කර වත්මන් සැකසුම් සමඟ සංයුක්ත කරන්න", + "message": "මේඝ ආචයනයෙන් ආයාත කර වත්මන් සැකසුම් වලට ඒකාබද්ධ කරන්න", "description": "tooltip" }, "cloudNoData": { @@ -1208,11 +1232,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 +1244,7 @@ "description": "for generic 'Apply changes' buttons" }, "genericRevert": { - "message": "Revert", + "message": "ප්‍රතිවර්තනය", "description": "for generic 'Revert' buttons" }, "genericBytes": { @@ -1228,51 +1252,51 @@ "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": { - "message": "Type a shortcut", + "message": "කෙටිමඟක් ලියන්න", "description": "Placeholder string for input field used to capture a keyboard shortcut" }, "genericMergeViewScrollLock": { - "message": "Toggle locked scrolling", + "message": "අගුළු දැමූ අනුචලනය ටොගල් කරන්න", "description": "Tooltip for the button used to lock scrolling between the views in the 'My rules' pane" }, "genericCopyToClipboard": { - "message": "පසුරුපුවරුවට පිටපත් කරන්න", + "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": { - "message": "Toggle cosmetic filtering", + "message": "රූපලාවන්‍ය පෙරහන ටොගල් කරන්න", "description": "Label for keyboard shortcut used to toggle cosmetic filtering" }, "toggleJavascript": { - "message": "Toggle JavaScript", + "message": "ජාවාස්ක්‍රිප්ට් ටොගල් කරන්න", "description": "Label for keyboard shortcut used to toggle no-scripting switch" }, "relaxBlockingMode": { - "message": "Relax blocking mode", + "message": "අවහිර කිරීමේ මාදිලිය ලිහිල් කරන්න", "description": "Label for keyboard shortcut used to relax blocking mode" }, "storageUsed": { - "message": "Storage used: {{value}} {{unit}}", + "message": "ආචයනය භාවිතය: {{value}} {{unit}}", "description": " In Setting pane, renders as (example): Storage used: 13.2 MB" }, "KB": { @@ -1292,11 +1316,11 @@ "description": "Message used in frame placeholders" }, "linterMainReport": { - "message": "Errors: {{count}}", + "message": "දෝෂ: {{count}}", "description": "Summary of number of errors as reported by the linter " }, "unprocessedRequestTooltip": { - "message": "Could not filter properly at browser launch. Reload the page to ensure proper filtering.", + "message": "බ්‍රව්සරය දියත් කිරීමේදී නිසි ලෙස පෙරීමට නොහැකි විය. නිසි පෙරහන සහතික කිරීම සඳහා පිටුව නැවත පූරණය කරන්න.", "description": "A warning which will appear in the popup panel if needed" }, "dummy": { diff --git a/src/_locales/sk/messages.json b/src/_locales/sk/messages.json index ab778d9d25cf9..997b1c7bec35e 100644 --- a/src/_locales/sk/messages.json +++ b/src/_locales/sk/messages.json @@ -340,11 +340,11 @@ "description": "Section for controlling user interface appearance" }, "settingsThemeLabel": { - "message": "Téma", + "message": "Motív", "description": "Label for checkbox to enable a custom dark theme" }, "settingsThemeAccent0Label": { - "message": "Vlastná farba témy", + "message": "Vlastná farba motívu", "description": "Label for checkbox to pick an accent color" }, "settingsCloudStorageEnabledPrompt": { @@ -372,7 +372,7 @@ "description": "" }, "settingPerSiteSwitchGroupSynopsis": { - "message": "Tieto predvolené správania môžu byť prepísané u jednotlivých stránkach", + "message": "Tieto predvolené správania môžu byť prepísané na jednotlivých stránkach", "description": "" }, "settingsNoCosmeticFilteringPrompt": { @@ -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" @@ -1080,7 +1084,7 @@ "description": "English: Reset to default settings..." }, "aboutRestoreDataConfirm": { - "message": "Všetky vaše nastavenia budú prepísané pomocou dáta zálohovaných dňa {{time}} a uBlock sa reštartne.\n\nPrepísať všetky existujúce nastavenia pomocou zálohovaných dát?", + "message": "Všetky vaše nastavenia budú prepísané dátami zálohovanými {{time}} a uBlock sa reštartuje.\n\nPrepísať všetky existujúce nastavenia pomocou zálohovaných dát?", "description": "Message asking user to confirm restore" }, "aboutRestoreDataError": { @@ -1187,6 +1191,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Dôvod:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Škodlivé", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Sledovač", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Pochybné", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exportovať do cloudového úložiska", "description": "tooltip" diff --git a/src/_locales/sl/messages.json b/src/_locales/sl/messages.json index bb2cfa2e156d5..f804810067d4f 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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Izvozi v shrambe oblaka", "description": "tooltip" diff --git a/src/_locales/so/messages.json b/src/_locales/so/messages.json index b8c9c13bcef31..86636dd3e9f03 100644 --- a/src/_locales/so/messages.json +++ b/src/_locales/so/messages.json @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "{{value}} saac kahor", "description": "tooltip" diff --git a/src/_locales/sq/messages.json b/src/_locales/sq/messages.json index 3fc972c4b03cb..2e6af1c4620eb 100644 --- a/src/_locales/sq/messages.json +++ b/src/_locales/sq/messages.json @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Krijoj raport të ri", + "message": "Krijoj raport të ri në GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Gjej raporte të ngjashme", + "message": "Gjej raporte të ngjashme në GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Verifikoni a është raportuar më parë problemi që të mos i lodhni vullnetarët e tjerë me të njëjtat gjëra.", + "message": "Verifikoni a është raportuar edhe më parë që të mos i lodhni vullnetarët e tjerë me të njëjtat probleme. Shënim: kur klikoni butonin, origjina e faqes do të dërgohet në GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Arsye:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Me qëllim të keq", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Gjurmues", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "I pandershëm", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Eksportoni në renë informatike", "description": "tooltip" diff --git a/src/_locales/sr/messages.json b/src/_locales/sr/messages.json index 35e56fc77a59b..0cfd081fa536f 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,26 @@ "message": "Настави", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Блокирана страница жели да преусмери на други сајт. Ако одлучите да наставите, ићи ћете директно на: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Извези у складиште у облаку", "description": "tooltip" diff --git a/src/_locales/sv/messages.json b/src/_locales/sv/messages.json index 37a8070e4e476..18242867a9372 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. Lätt för både processor och minne.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "dashboardName": { @@ -116,7 +116,7 @@ "description": "English: Click to open the dashboard" }, "popupTipZapper": { - "message": "Gå till elementzapperläge", + "message": "Gå in i elementzapperläge", "description": "Tooltip for the element-zapper icon in the popup panel" }, "popupTipPicker": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Skapa ny rapport", + "message": "Skapa ny rapport på GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Hitta liknande rapporter", + "message": "Hitta liknande rapporter på GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -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": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "För att undvika att belasta volontärer med dubbletter av rapporter, kontrollera att problemet inte redan har rapporterats.", + "message": "För att undvika att belasta volontärer med dubbletter av rapporter, kontrollera att problemet inte redan har rapporterats. Observera: om du klickar på knappen kommer sidans ursprung att skickas till GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Anledning:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Illvillig", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Spårare", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Vanhedrande", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Exportera till molnlagring", "description": "tooltip" diff --git a/src/_locales/sw/messages.json b/src/_locales/sw/messages.json index ad3e42820fc88..29c1508598031 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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Hamisha hadi hifadhi ya wingu", "description": "tooltip" diff --git a/src/_locales/ta/messages.json b/src/_locales/ta/messages.json index c76293554b4ca..4efbf7c209204 100644 --- a/src/_locales/ta/messages.json +++ b/src/_locales/ta/messages.json @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "மேகக்கணினி சேமிப்பகத்திற்கு ஏற்று", "description": "tooltip" diff --git a/src/_locales/te/messages.json b/src/_locales/te/messages.json index 0f4e085e0c91a..68c48afe08438 100644 --- a/src/_locales/te/messages.json +++ b/src/_locales/te/messages.json @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "క్లౌడ్ లో పొందుపరచు", "description": "tooltip" diff --git a/src/_locales/th/messages.json b/src/_locales/th/messages.json index 268cd4da0366d..10fe0d229849f 100644 --- a/src/_locales/th/messages.json +++ b/src/_locales/th/messages.json @@ -28,7 +28,7 @@ "description": "appears as tab name in dashboard" }, "3pPageName": { - "message": "ตัวกรองจากที่อื่น", + "message": "รายการตัวกรอง", "description": "appears as tab name in dashboard" }, "1pPageName": { @@ -36,19 +36,19 @@ "description": "appears as tab name in dashboard" }, "rulesPageName": { - "message": "กฎของฉัน", + "message": "เงื่อนไขของฉัน", "description": "appears as tab name in dashboard" }, "whitelistPageName": { - "message": "รายการยกเว้น", + "message": "เว็บไซต์ที่เชื่อถือได้", "description": "appears as tab name in dashboard" }, "shortcutsPageName": { - "message": "Shortcuts", + "message": "ทางลัด", "description": "appears as tab name in dashboard" }, "statsPageName": { - "message": "uBlock₀ — ประวัติ", + "message": "uBlock₀ — บันทึก", "description": "Title for the logger window" }, "aboutPageName": { @@ -56,11 +56,11 @@ "description": "appears as tab name in dashboard" }, "supportPageName": { - "message": "ช่วยเหลือ", + "message": "สนับสนุน", "description": "appears as tab name in dashboard" }, "assetViewerPageName": { - "message": "uBlock₀ — Asset viewer", + "message": "uBlock₀ — โปรแกรมดูสิ่งที่ถือครอง", "description": "Title for the asset viewer page" }, "advancedSettingsPageName": { @@ -68,7 +68,7 @@ "description": "Title for the advanced settings page" }, "popupPowerSwitchInfo": { - "message": "Click: เปิด/ปิดการทำงานของ uBlock₀ สำหรับเว็บไซต์นี้ \nCtrl+click: ปิดการทำงานของ uBlock₀ เฉพาะหน้าเว็บนี้", + "message": "คลิก: ปิด/เปิดการทำงานของ uBlock₀ สำหรับเว็บไซต์นี้ \nCtrl+คลิก: ปิดการทำงานของ uBlock₀ เฉพาะหน้าเว็บนี้", "description": "English: Click: disable/enable uBlock₀ for this site.\n\nCtrl+click: disable uBlock₀ only on this page." }, "popupPowerSwitchInfo1": { @@ -168,7 +168,7 @@ "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoRemoteFonts": { - "message": "Toggle the blocking of remote fonts for this site", + "message": "สลับเป็นฟอนต์เครื่องที่บล็อกสำหรับเว็บนี้", "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoRemoteFonts1": { @@ -384,7 +384,7 @@ "description": "" }, "settingsNoRemoteFontsPrompt": { - "message": "Block remote fonts", + "message": "ฟอนต์เครื่องที่บล็อก", "description": "" }, "settingsNoScriptingPrompt": { @@ -396,7 +396,7 @@ "description": "background information: https://github.com/gorhill/uBlock/issues/3150" }, "settingsUncloakCnamePrompt": { - "message": "Uncloak canonical names", + "message": "เปิดเผยชื่อตามหลักเกณฑ์", "description": "background information: https://github.com/uBlockOrigin/uBlock-issues/issues/1513" }, "settingsAdvanced": { @@ -420,11 +420,11 @@ "description": "English: Last backup:" }, "3pListsOfBlockedHostsPrompt": { - "message": "{{netFilterCount}} network filters + {{cosmeticFilterCount}} cosmetic filters from:", + "message": "{{netFilterCount}} ตัวกรองเครือข่าย + {{cosmeticFilterCount}} ตกแต่งตัวกรองจาก:", "description": "Appears at the top of the _3rd-party filters_ pane" }, "3pListsOfBlockedHostsPerListStats": { - "message": "{{used}} used out of {{total}}", + "message": "{{used}} ใช้ไปแล้วจาก {{total}}", "description": "Appears aside each filter list in the _3rd-party filters_ pane" }, "3pAutoUpdatePrompt1": { @@ -484,11 +484,11 @@ "description": "Filter lists section name" }, "3pGroupSocial": { - "message": "Social widgets", + "message": "วิดเจ็ตโซเชียล", "description": "Filter lists section name" }, "3pGroupCookies": { - "message": "Cookie notices", + "message": "คำประกาศการใช้คุ้กกี้", "description": "Filter lists section name" }, "3pGroupAnnoyances": { @@ -532,27 +532,27 @@ "description": "used as a tooltip for the spinner icon beside a list" }, "3pNetworkError": { - "message": "A network error prevented the resource from being updated.", + "message": "ความผิดพลาดของเครือข่ายขวางกั้นการอัปเดต", "description": "used as a tooltip for error icon beside a list" }, "1pTrustWarning": { - "message": "Do not add filters from untrusted sources.", + "message": "ไม่อนุญาตให้เพิ่มตัวกรองจากแหล่งที่มาที่ไม่น่าเชื่อถือ", "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { - "message": "Enable my custom filters", + "message": "เปิดใช้งานการปรับแต่งตัวกรองของฉัน", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { - "message": "Allow custom filters requiring trust", + "message": "อนุญาตการปรับแต่งตัวกรองที่ต้องมีความน่าเชื่อถือ", "description": "Label for the checkbox use to trust the content of 'My filters' list" }, "1pImport": { - "message": "Import and append…", + "message": "นำเข้าและเพิ่มต่อท้าย…", "description": "Button in the 'My filters' pane" }, "1pExport": { - "message": "Export…", + "message": "ส่งออก", "description": "Button in the 'My filters' pane" }, "1pExportFilename": { @@ -560,7 +560,7 @@ "description": "English: my-ublock-static-filters_{{datetime}}.txt" }, "1pApplyChanges": { - "message": "Apply changes", + "message": "นำไปใช้", "description": "English: Apply changes" }, "rulesPermanentHeader": { @@ -576,7 +576,7 @@ "description": "This will remove all temporary rules" }, "rulesCommit": { - "message": "Commit", + "message": "ยืนยัน", "description": "This will persist temporary rules" }, "rulesEdit": { @@ -604,11 +604,11 @@ "description": "default file name to use" }, "rulesHint": { - "message": "List of your dynamic filtering rules.", + "message": "รายการเงื่อนไขตัวกรองแบบไดนามิกของคุณ", "description": "English: List of your dynamic filtering rules." }, "rulesFormatHint": { - "message": "Rule syntax: source destination type action (full documentation).", + "message": "ข้อกำหนดเงื่อนไข: การดำเนินการประเภทแหล่งปลายทาง (เอกสารฉบับเต็ม)", "description": "English: dynamic rule syntax and full documentation." }, "rulesSort": { @@ -668,7 +668,7 @@ "description": "Appears in the logger's tab selector" }, "logBehindTheScene": { - "message": "Tabless", + "message": "ตาราง", "description": "Pretty name for behind-the-scene network requests" }, "loggerCurrentTab": { @@ -680,19 +680,19 @@ "description": "Tooltip for the reload button in the logger page" }, "loggerDomInspectorTip": { - "message": "Toggle the DOM inspector", + "message": "สลับตัวตรวจสอบ DOM", "description": "Tooltip for the DOM inspector button in the logger page" }, "loggerPopupPanelTip": { - "message": "Toggle the popup panel", + "message": "สลับแผงป๊อปอัป", "description": "Tooltip for the popup panel button in the logger page" }, "loggerInfoTip": { - "message": "uBlock Origin wiki: The logger", + "message": "uBlock Origin wiki: ตัวลงบันทึก", "description": "Tooltip for the top-right info label in the logger page" }, "loggerClearTip": { - "message": "Clear logger", + "message": "ล้างบันทึก", "description": "Tooltip for the eraser in the logger page; used to blank the content of the logger" }, "loggerPauseTip": { @@ -700,23 +700,23 @@ "description": "Tooltip for the pause button in the logger page" }, "loggerUnpauseTip": { - "message": "Unpause logger", + "message": "ยกเลิกการหยุดบันทึกชั่วคราว", "description": "Tooltip for the play button in the logger page" }, "loggerRowFiltererButtonTip": { - "message": "Toggle logger filtering", + "message": "สลับตัวกรองบันทึก", "description": "Tooltip for the row filterer button in the logger page" }, "logFilterPrompt": { - "message": "filter logger content", + "message": "ตัวกรองเนื้อหาบันทึก", "description": "Placeholder string for logger output filtering input field" }, "loggerRowFiltererBuiltinTip": { - "message": "Logger filtering options", + "message": "ตัวเลือกตัวกรองบันทึก", "description": "Tooltip for the button to bring up logger output filtering options" }, "loggerRowFiltererBuiltinNot": { - "message": "Not", + "message": "ไม่", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltinEventful": { @@ -724,19 +724,19 @@ "description": "A keyword in the built-in row filtering expression: all items corresponding to uBO doing something (blocked, allowed, redirected, etc.)" }, "loggerRowFiltererBuiltinBlocked": { - "message": "blocked", + "message": "บล๊อกอยู่", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltinAllowed": { - "message": "allowed", + "message": "อนุญาต", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltinModified": { - "message": "modified", + "message": "แก้ไขแล้ว", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltin1p": { - "message": "1st-party", + "message": "ฝ่ายที่ 1", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltin3p": { @@ -760,19 +760,19 @@ "description": "Label to identify a rule field" }, "loggerEntryDetailsContext": { - "message": "Context", + "message": "บริบท", "description": "Label to identify a context field (typically a hostname)" }, "loggerEntryDetailsRootContext": { - "message": "Root context", + "message": "ปฐมบท", "description": "Label to identify a root context field (typically a hostname)" }, "loggerEntryDetailsPartyness": { - "message": "Partyness", + "message": "การรวมกลุ่ม", "description": "Label to identify a field providing partyness information" }, "loggerEntryDetailsType": { - "message": "Type", + "message": "ประเภท", "description": "Label to identify the type of an entry" }, "loggerEntryDetailsURL": { @@ -780,11 +780,11 @@ "description": "Label to identify the URL of an entry" }, "loggerURLFilteringHeader": { - "message": "URL rule", + "message": "เงื่อนไข URL", "description": "Small header to identify the dynamic URL filtering section" }, "loggerURLFilteringContextLabel": { - "message": "Context:", + "message": "บริบท:", "description": "Label for the context selector" }, "loggerURLFilteringTypeLabel": { @@ -792,11 +792,11 @@ "description": "Label for the type selector" }, "loggerStaticFilteringHeader": { - "message": "Static filter", + "message": "ตัวกรองแบบคงที่", "description": "Small header to identify the static filtering section" }, "loggerStaticFilteringSentence": { - "message": "{{action}} network requests of {{type}} {{br}}which URL address matches {{url}} {{br}}and which originates {{origin}},{{br}}{{importance}} there is a matching exception filter.", + "message": "{{action}} การร้องขอเครือข่ายของ {{type}} {{br}}ซึ่ง URL ตรงกันกับ {{url}} {{br}}และมีต้นทางที่ {{origin}},{{br}}{{importance}} มีตัวกรองที่ยกเว้นตรงกัน", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartBlock": { @@ -808,23 +808,23 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartType": { - "message": "type “{{type}}”", + "message": "ประเภท “{{type}}”", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartAnyType": { - "message": "any type", + "message": "ประเภทใดก็ได้", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartOrigin": { - "message": "from “{{origin}}”", + "message": "จาก “{{origin}}”", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartAnyOrigin": { - "message": "from anywhere", + "message": "จากที่ใดก็ได้", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartNotImportant": { - "message": "except when", + "message": "ยกเว้นเมื่อ", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartImportant": { @@ -832,31 +832,31 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringFinderSentence1": { - "message": "Static filter {{filter}} found in:", + "message": "ตัวกรองแบบคงที่ {{filter}} พบใน:", "description": "Below this sentence, the filter list(s) in which the filter was found" }, "loggerStaticFilteringFinderSentence2": { - "message": "Static filter could not be found in any of the currently enabled filter lists", + "message": "ตัวกรองแบบคงที่ไม่พบในรายการตัวกรองที่เปิดอยู่", "description": "Message to show when a filter cannot be found in any filter lists" }, "loggerSettingDiscardPrompt": { - "message": "Logger entries which do not fulfill all three conditions below will be automatically discarded:", + "message": "รายการบันทึกที่ไม่ครบถ้วนทั้ง 3 เงื่อนไขตามด้านล่างจะถูกละทิ้งโดยอัตโนมัติ", "description": "Logger setting: A sentence to describe the purpose of the settings below" }, "loggerSettingPerEntryMaxAge": { - "message": "Preserve entries from the last {{input}} minutes", + "message": "สงวนรายการ {{input}} นาที", "description": "A logger setting" }, "loggerSettingPerTabMaxLoads": { - "message": "Preserve at most {{input}} page loads per tab", + "message": "สงวนจำนวนมากที่สุด {{input}} หน้าโหลดต่อแท็บ", "description": "A logger setting" }, "loggerSettingPerTabMaxEntries": { - "message": "Preserve at most {{input}} entries per tab", + "message": "สงวนจำนวนมากที่สุด {{input}} รายการต่อแท็บ", "description": "A logger setting" }, "loggerSettingPerEntryLineCount": { - "message": "Use {{input}} lines per entry in vertically expanded mode", + "message": "ใช้ {{input}} บรรทัดต่อรายการในโหมดการขยายแนวตั้ง", "description": "A logger setting" }, "loggerSettingHideColumnsPrompt": { @@ -872,11 +872,11 @@ "description": "A label for the filter or rule column" }, "loggerSettingHideColumnContext": { - "message": "{{input}} Context", + "message": "{{input}} บริบท", "description": "A label for the context column" }, "loggerSettingHideColumnPartyness": { - "message": "{{input}} Partyness", + "message": "{{input}} การจัดกลุ่ม", "description": "A label for the partyness column" }, "loggerExportFormatList": { @@ -888,11 +888,11 @@ "description": "Label for radio-button to pick export format" }, "loggerExportEncodePlain": { - "message": "Plain", + "message": "ธรรมดา", "description": "Label for radio-button to pick export text format" }, "loggerExportEncodeMarkdown": { - "message": "Markdown", + "message": "ทำเครื่องหมายลง", "description": "Label for radio-button to pick export text format" }, "supportOpenButton": { @@ -904,7 +904,7 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "ค้นหารายงานคล้ายกันบน GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -912,31 +912,31 @@ "description": "Header of 'Documentation' section in Support pane" }, "supportS1P1": { - "message": "Read the documentation at uBlock/wiki to learn about all of uBlock Origin's features.", + "message": "อ่านเอกสารข้อมูลที่ uBlock/wiki เพื่อเรียนรู้ฟีเจอร์ทั้งหมดของ uBlock Origin", "description": "First paragraph of 'Documentation' section in Support pane" }, "supportS2H": { - "message": "Questions and support", + "message": "คำถามและการสนับสนุน", "description": "Header of 'Questions and support' section in Support pane" }, "supportS2P1": { - "message": "Answers to questions and other kinds of help support is provided on the subreddit /r/uBlockOrigin.", + "message": "การตอบคำถามและการสนับสนุนอื่น ๆ ที่เตรียมไว้ให้บน subreddit /r/uBlockOrigin", "description": "First paragraph of 'Questions and support' section in Support pane" }, "supportS3H": { - "message": "Filter issues/website is broken", + "message": "คัดกรองปัญหา/เว็บไซต์ที่ไม่สมบูรณ์", "description": "Header of 'Filter issues' section in Support pane" }, "supportS3P1": { - "message": "Report filter issues with specific websites to the uBlockOrigin/uAssets issue tracker. Requires a GitHub account.", + "message": "รายงานปัญหาการกรองด้วยเว็บไซต์เฉพาะที่ uBlockOrigin/uAssets ตัวติดตามปัญหา. ต้องใช้บัญชี GitHub", "description": "First paragraph of 'Filter issues' section in Support pane" }, "supportS3P2": { - "message": "Important: Avoid using other similarly-purposed blockers along with uBlock Origin, as this may cause filter issues on specific websites.", + "message": "สำคัญ: หลีกเลี่ยงการใช้ตัวบล๊อกอื่น ๆ ร่วมกันกับ uBlock Origin ซึ่งอาจทำให้เกิดปัญหาในการกรองของหน้าเว็บไซต์ที่ต้องการ", "description": "Second paragraph of 'Filter issues' section in Support pane" }, "supportS3P3": { - "message": "Tips: Be sure your filter lists are up to date. The logger is the primary tool to diagnose filter-related issues.", + "message": "เคล็ดลับ: ให้แน่ใจว่ารายการตัวกรองของคุณได้รับการอัปเดตแล้ว ตัวบันทึก เป็นเครื่องมือหลักในการวินิจฉัยปัญหาที่เกี่ยวเนื่อง", "description": "Third paragraph of 'Filter issues' section in Support pane" }, "supportS4H": { @@ -944,43 +944,43 @@ "description": "Header of 'Bug report' section in Support pane" }, "supportS4P1": { - "message": "Report issues with uBlock Origin itself to the uBlockOrigin/uBlock-issue issue tracker. Requires a GitHub account.", + "message": "รายงานปัญหาด้วย uBlock Origin เอง uBlockOrigin/uBlock-issue ปัญหาตัวติดตาม. ต้องใช้บัญชี GitHub", "description": "First paragraph of 'Bug report' section in Support pane" }, "supportS5H": { - "message": "Troubleshooting Information", + "message": "ข้อมูลการแก้ไขปัญหา", "description": "Header of 'Troubleshooting Information' section in Support pane" }, "supportS5P1": { - "message": "Below is technical information that might be useful when volunteers are trying to help you solve a problem.", + "message": "ด้านล่างนี้เป็นข้อมูลทางเทคนิคซึ่งอาจเป็นประโยชน์ในกรณีที่อาสาสมัครพยายามให้การช่วยเหลือในการแก้ไขปัญหาให้คุณ", "description": "First paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS5P2": { - "message": "Important: Potentially private or sensitive information is redacted by default. Redacted information may make it more difficult to solve a problem.", + "message": "สำคัญ: ข้อมูลที่อาจเป็นความลับหรือละเอียดอ่อนจะถูกแก้ไขตามค่าเริ่มต้น ข้อมูลที่แก้ไขอาจะทำให้การแก้ไขปัญหายากขึ้น", "description": "Second paragraph of 'Troubleshooting Information' section in Support pane" }, "supportS6H": { - "message": "Report a filter issue", + "message": "รายงานปัญหาตัวกรอง", "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "เพื่อเป็นการลดภาระอาสาสมัครจากการรายงานซ้ำซ้อน โปรดตรวจสอบก่อนว่าปัญหาดังกล่าวได้รับการรายงานไปแล้วหรือยัง หมายเหตุ: คลิกที่ปุ่มจะเป็นการส่งต้นทางของหน้าเว็บไปยัง GitHub", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { - "message": "Filter lists are updated daily. Be sure your issue has not already been addressed in the most recent filter lists.", + "message": "มีการอัปเดตรายการตัวกรองประจำวัน ให้แน่ใจว่าปัญหาของคุณยังไม่ได้ระบุไว้ในรายการตัวกรองล่าสุด", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S2": { - "message": "Verify that the issue still exists after reloading the problematic webpage.", + "message": "ตรวจสอบว่าปัญหายังคงอยู่หลังจากมีการโหลดหน้าเว็บเพจที่มีปัญหาซ้ำแล้ว", "description": "A paragraph in the filter issue reporter section" }, "supportS6URL": { - "message": "Address of the web page:", + "message": "ที่อยู่ของเว็บเพจ:", "description": "Label for the URL of the page" }, "supportS6Select1": { - "message": "The web page…", + "message": "เว็บเพจ…", "description": "Label for widget to select type of issue" }, "supportS6Select1Option0": { @@ -988,31 +988,35 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option1": { - "message": "Shows ads or ad leftovers", + "message": "แสดงโฆษณาหรือสิ่งที่ตกค้างอยู่", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "Has overlays or other nuisances", + "message": "มีโอเวอร์เลย์หรือสิ่งอื่น ๆ ที่รบกวน", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { - "message": "Detects uBlock Origin", + "message": "ตรวจหา uBlock Origin", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { - "message": "Has privacy-related issues", + "message": "มีปัญหาที่เกี่ยวเนื่องกับความเป็นส่วนตัว", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "Malfunctions when uBlock Origin is enabled", + "message": "ความผิดปกติเมื่อเปิดใช้งาน uBlock Origin", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { - "message": "Opens unwanted tabs or windows", + "message": "เปิดแท็บหรือหน้าต่างที่ไม่ต้องการ", + "description": "An entry in the widget used to select the type of issue" + }, + "supportS6Select1Option7": { + "message": "นำไปสู่แบดแวร์ ฟิชชิ่ง", "description": "An entry in the widget used to select the type of issue" }, "supportS6Checkbox1": { - "message": "Label the web page as “NSFW” (“Not Safe For Work”)", + "message": "ติดป้ายเว็บเพจว่าเป็น “NSFW” (“ไม่ปลอดภัยกับงาน (Not Safe For Work)”)", "description": "A checkbox to use for NSFW sites" }, "supportRedact": { @@ -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": { @@ -1056,7 +1060,7 @@ "description": "Shown in the About pane" }, "aboutCDNs": { - "message": "uBO's own filter lists are freely hosted on the following CDNs:", + "message": "uBO's ถือครองรายการตัวกรองที่เก็บไว้ที่ CDNs:", "description": "Shown in the About pane" }, "aboutCDNsInfo": { @@ -1064,7 +1068,7 @@ "description": "Shown in the About pane" }, "aboutBackupDataButton": { - "message": "Back up to file…", + "message": "แบ็กอัพไปยังไฟล์…", "description": "Text for button to create a backup of all settings" }, "aboutBackupFilename": { @@ -1072,27 +1076,27 @@ "description": "English: my-ublock-backup_{{datetime}}.txt" }, "aboutRestoreDataButton": { - "message": "Restore from file…", + "message": "คืนค่าจากไฟล์…", "description": "English: Restore from file..." }, "aboutResetDataButton": { - "message": "Reset to default settings…", + "message": "ปรับเป็นการตั้งค่าเริ่มต้น", "description": "English: Reset to default settings..." }, "aboutRestoreDataConfirm": { - "message": "All your settings will be overwritten using data backed up on {{time}}, and uBlock₀ will restart.\n\nOverwrite all existing settings using backed up data?", + "message": "การตั้งค่าทั้งหมดของคุณจะถูกเขียนทับโดยใช้ข้อมูลที่แบ็กอัพไว้บน {{time}} และ uBlock₀ จะรีสตาร์ท\n\nเขียนทับการตั้งค่าทั้งหมดด้วยข้อมูลที่แบ็กอัพหรือไม่?", "description": "Message asking user to confirm restore" }, "aboutRestoreDataError": { - "message": "The data could not be read or is invalid", + "message": "ไม่สามารถอ่านข้อมูลได้หรือข้อมูลไม่ถูกต้อง", "description": "Message to display when an error occurred during restore" }, "aboutResetDataConfirm": { - "message": "All your settings will be removed, and uBlock₀ will restart.\n\nReset uBlock₀ to factory settings?", + "message": "การตั้งค่าทั้งหมดของคุณจะถูกลบทิ้ง และ uBlock₀ จะรีสตาร์ท\n\nรีเซ็ต uBlock₀ เป็นค่าเริ่มต้นโรงงาน?", "description": "Message asking user to confirm reset" }, "errorCantConnectTo": { - "message": "Network error: {{msg}}", + "message": "เครือข่ายผิดพลาด: {{msg}}", "description": "English: Network error: {{msg}}" }, "subscriberConfirm": { @@ -1128,11 +1132,11 @@ "description": "English: {{value}} days ago" }, "showDashboardButton": { - "message": "Show Dashboard", + "message": "แสดงแดชบอร์ด", "description": "Firefox/Fennec-specific: Show Dashboard" }, "showNetworkLogButton": { - "message": "Show Logger", + "message": "แสดงบันทึก", "description": "Firefox/Fennec-specific: Show Logger" }, "fennecMenuItemBlockingOff": { @@ -1152,7 +1156,7 @@ "description": "Used in the strict-blocking page" }, "docblockedNoParamsPrompt": { - "message": "without parameters", + "message": "ไม่ระบุพารามิเตอร์", "description": "label to be used for the parameter-less URL: https://cloud.githubusercontent.com/assets/585534/9832014/bfb1b8f0-593b-11e5-8a27-fba472a5529a.png" }, "docblockedFoundIn": { @@ -1168,7 +1172,7 @@ "description": "English: Close this window" }, "docblockedDontWarn": { - "message": "Don't warn me again about this site", + "message": "ไม่ต้องแจ้งเตือนอีกเกี่ยวกับเว็บไซต์นี้", "description": "Label for checkbox in document-blocked page" }, "docblockedProceed": { @@ -1187,16 +1191,36 @@ "message": "ดำเนินการ", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "เว็บเพจที่บล๊อกต้องการเด้งไปเว็บไซต์อื่น หากคุณต้องการดำเนินการต่อ คุณจะถูกนำทางโดยตรงไปที่: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { - "message": "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": { @@ -1212,15 +1236,15 @@ "description": "A warning to users at the top of 'Advanced settings' page" }, "genericSubmit": { - "message": "Submit", + "message": "ยืนยัน", "description": "for generic 'Submit' buttons" }, "genericApplyChanges": { - "message": "Apply changes", + "message": "ใช้การเปลี่ยนแปลง", "description": "for generic 'Apply changes' buttons" }, "genericRevert": { - "message": "Revert", + "message": "คืนค่ากลับ", "description": "for generic 'Revert' buttons" }, "genericBytes": { @@ -1228,7 +1252,7 @@ "description": "" }, "contextMenuBlockElementInFrame": { - "message": "Block element in frame…", + "message": "บล๊อกองค์ประกอบในเฟรม…", "description": "An entry in the browser's contextual menu" }, "contextMenuSubscribeToList": { @@ -1244,15 +1268,15 @@ "description": "A context menu entry, to view the source code of the target resource" }, "shortcutCapturePlaceholder": { - "message": "Type a shortcut", + "message": "พิมพ์ทางลัด", "description": "Placeholder string for input field used to capture a keyboard shortcut" }, "genericMergeViewScrollLock": { - "message": "Toggle locked scrolling", + "message": "สลับการล็อกการเลื่อน", "description": "Tooltip for the button used to lock scrolling between the views in the 'My rules' pane" }, "genericCopyToClipboard": { - "message": "Copy to clipboard", + "message": "คัดลอกไปยังคลิปบอร์ด", "description": "Label for buttons used to copy something to the clipboard" }, "genericSelectAll": { @@ -1260,15 +1284,15 @@ "description": "Label for buttons used to select all text in editor" }, "toggleCosmeticFiltering": { - "message": "Toggle cosmetic filtering", + "message": "สลับตัวกรองการตกแต่ง", "description": "Label for keyboard shortcut used to toggle cosmetic filtering" }, "toggleJavascript": { - "message": "Toggle JavaScript", + "message": "สลับ JavaScript", "description": "Label for keyboard shortcut used to toggle no-scripting switch" }, "relaxBlockingMode": { - "message": "Relax blocking mode", + "message": "ผ่อนปรนโหมดการบล๊อก", "description": "Label for keyboard shortcut used to relax blocking mode" }, "storageUsed": { @@ -1292,11 +1316,11 @@ "description": "Message used in frame placeholders" }, "linterMainReport": { - "message": "Errors: {{count}}", + "message": "ข้อผิดพลาด: {{count}}", "description": "Summary of number of errors as reported by the linter " }, "unprocessedRequestTooltip": { - "message": "Could not filter properly at browser launch. Reload the page to ensure proper filtering.", + "message": "ไม่สามารถกรองได้สมบูรณ์เมื่อตอนเริ่มเบราว์เซอร์ โหลดหน้าเว็บใหม่เพื่อให้การกรองสมบูรณ์", "description": "A warning which will appear in the popup panel if needed" }, "dummy": { diff --git a/src/_locales/tr/messages.json b/src/_locales/tr/messages.json index 31f6aa55ca6ee..114616b189bb7 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": { @@ -632,11 +632,11 @@ "description": "A concise description of the 'Trusted sites' pane." }, "whitelistImport": { - "message": "İçe aktar ve ekle", + "message": "İçe aktar ve ekle…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExport": { - "message": "Dışa aktar", + "message": "Dışa aktar…", "description": "Button in the 'Trusted sites' pane" }, "whitelistExportFilename": { @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Yeni rapor oluştur", + "message": "GitHub üzerinde yeni rapor oluştur", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Benzer raporları bul", + "message": "GitHub'da benzer raporları bul.", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "Gönüllülere aynı raporlarla sıkıntı vermemek için, lütfen sorunun daha önce bildirilmediğinden emin olun.", + "message": "Gönüllüleri yinelenen bildirimlerle meşgul etmemek için lütfen sorunun daha önce bildirilip bildirilmediğini kontrol edin.\nNot: Butona tıklamak, sayfanın kaynağının GitHub'a gönderilmesine neden olacaktır.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Sebep:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Kötü niyetli", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "İzleyici", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Güvenilmez", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Bulut depolamaya aktar", "description": "tooltip" @@ -1264,7 +1288,7 @@ "description": "Label for keyboard shortcut used to toggle cosmetic filtering" }, "toggleJavascript": { - "message": "JavaScript'i Aç/Kapa", + "message": "JavaScript'i Aç/Kapat", "description": "Label for keyboard shortcut used to toggle no-scripting switch" }, "relaxBlockingMode": { diff --git a/src/_locales/uk/messages.json b/src/_locales/uk/messages.json index c78caea505588..f985433fc4ee7 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,26 @@ "message": "Продовжити", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "Заблокована сторінка хоче переадресувати на інший сайт. Якщо ви вирішите продовжити, ви перейдете безпосередньо на: {{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "Причина:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Зловмисні", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Трекер", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Сумнівний вміст", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Експортувати до хмарного сховища", "description": "tooltip" diff --git a/src/_locales/ur/messages.json b/src/_locales/ur/messages.json index 6fbc6fcc824a5..367155757aedc 100644 --- a/src/_locales/ur/messages.json +++ b/src/_locales/ur/messages.json @@ -900,11 +900,11 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "Create new report", + "message": "Create new report on GitHub", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { - "message": "Find similar reports", + "message": "Find similar reports on GitHub", "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { @@ -964,7 +964,7 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported.", + "message": "To avoid burdening volunteers with duplicate reports, please verify that the issue has not already been reported. Note: clicking the button will cause the page's origin to be sent to GitHub.", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "کلاؤڈ سٹوریج میں برآمد کریں", "description": "tooltip" diff --git a/src/_locales/vi/messages.json b/src/_locales/vi/messages.json index 9c50188234059..24ece0fbf72d4 100644 --- a/src/_locales/vi/messages.json +++ b/src/_locales/vi/messages.json @@ -104,7 +104,7 @@ "description": "For the new mobile-friendly popup design" }, "popupBlockedSinceInstall_v2": { - "message": "Đã chặn từ khi cài đặt", + "message": "Bị chặn kể từ khi cài đặt", "description": "For the new mobile-friendly popup design" }, "popupDomainsConnected_v2": { @@ -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": "Bấm để 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": { @@ -176,7 +176,7 @@ "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoRemoteFonts2": { - "message": "Nhấp để không chặn phông tải về trên trang này", + "message": "Bấm để ngừng chặn remote fonts trên trang này", "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": "Phông tải về", + "message": "Remote fonts", "description": "Caption for the no-remote-fonts per-site switch" }, "popupNoScripting_v2": { @@ -380,7 +380,7 @@ "description": "" }, "settingsNoLargeMediaPrompt": { - "message": "Chặn yếu tố đa phương tiện lớn hơn {{input}} KB", + "message": "Chặn phần tử đa phương tiện kich thước lớn hơn {{input}} KB", "description": "" }, "settingsNoRemoteFontsPrompt": { @@ -404,7 +404,7 @@ "description": "Section for controlling advanced-user settings" }, "settingsAdvancedSynopsis": { - "message": "Những tính năng dành cho người dùng nâng cao", + "message": "Các tính năng chỉ phù hợp với kỹ thuật viên", "description": "Description of section controlling advanced-user settings" }, "settingsAdvancedUserSettings": { @@ -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,26 @@ "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" + }, + "docblockedReasonLabel": { + "message": "Reason:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "Malicious", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "Tracker", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "Disreputable", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "Xuất ra lưu trữ trực tuyến", "description": "tooltip" @@ -1240,7 +1264,7 @@ "description": "A context menu entry, present when large media elements have been blocked on the current site" }, "contextMenuViewSource": { - "message": "Xem mã nguồn", + "message": "Xem mã nguồn...", "description": "A context menu entry, to view the source code of the target resource" }, "shortcutCapturePlaceholder": { @@ -1272,7 +1296,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..79e9e692463c6 100644 --- a/src/_locales/zh_CN/messages.json +++ b/src/_locales/zh_CN/messages.json @@ -908,7 +908,7 @@ "description": "A clickable link in the filter issue reporter section" }, "supportS1H": { - "message": "使用说明", + "message": "文档", "description": "Header of 'Documentation' section in Support pane" }, "supportS1P1": { @@ -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" @@ -1028,7 +1032,7 @@ "description": "Link to privacy policy on GitHub (English)" }, "aboutChangelog": { - "message": "变更日志", + "message": "更新日志", "description": "" }, "aboutCode": { @@ -1187,6 +1191,26 @@ "message": "继续加载", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "被屏蔽的网页想重定向到另一个网站。如果您选择继续,将直接导航到:{{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "原因:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "恶意网站", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "跟踪器", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "不受信任", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "导出到云端储存", "description": "tooltip" diff --git a/src/_locales/zh_TW/messages.json b/src/_locales/zh_TW/messages.json index f07258b6a40cb..996a89c157381 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,11 +12,11 @@ "description": "English: uBlock₀ — Dashboard" }, "dashboardUnsavedWarning": { - "message": "警告!您有尚未儲存的變更", + "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": { @@ -44,7 +44,7 @@ "description": "appears as tab name in dashboard" }, "shortcutsPageName": { - "message": "快速鍵", + "message": "快捷鍵", "description": "appears as tab name in dashboard" }, "statsPageName": { @@ -68,15 +68,15 @@ "description": "Title for the advanced settings page" }, "popupPowerSwitchInfo": { - "message": "點擊:在此網站 停用/啟用 uBlock₀ 。\n\nCtrl + 點擊:僅在此頁面停用 uBlock₀ 。", + "message": "點擊:在這個網站停用/啟用 uBlock₀。\n\nCtrl + 點擊:僅在這個頁面停用 uBlock₀。", "description": "English: Click: disable/enable uBlock₀ for this site.\n\nCtrl+click: disable uBlock₀ only on this page." }, "popupPowerSwitchInfo1": { - "message": "點擊:在此網站停用 uBlock₀ 。\n\nCtrl + 點擊:僅在此頁面停用 uBlock₀ 。", + "message": "點擊:在這個網站停用 uBlock₀ 。\n\nCtrl + 點擊:僅在這個頁面停用 uBlock₀ 。", "description": "Message to be read by screen readers" }, "popupPowerSwitchInfo2": { - "message": "點擊以在此網站啟用 uBlock₀ 。", + "message": "點擊以在這個網站啟用 uBlock₀。", "description": "Message to be read by screen readers" }, "popupBlockedRequestPrompt": { @@ -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": { @@ -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": { @@ -164,7 +164,7 @@ "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoCosmeticFiltering2": { - "message": "點擊以啟用此網站的網頁元素過濾", + "message": "點擊以啟用這個網站的網頁元素過濾", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoRemoteFonts": { @@ -176,15 +176,15 @@ "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoRemoteFonts2": { - "message": "點擊以停止封鎖此網站的遠端字型", + "message": "點擊以解除封鎖這個網站的遠端字型", "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoScripting1": { - "message": "點擊以停用此網站的 JavaScript", + "message": "點擊以停用這個網站的 JavaScript", "description": "Tooltip for the no-scripting per-site switch" }, "popupTipNoScripting2": { - "message": "點擊以重新啟用此網站的 JavaScript ", + "message": "點擊以重新啟用這個網站的 JavaScript ", "description": "Tooltip for the no-scripting per-site switch" }, "popupNoPopups_v2": { @@ -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": { @@ -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": { @@ -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": { @@ -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": { @@ -468,7 +468,7 @@ "description": "English: Apply changes" }, "3pGroupDefault": { - "message": "內置", + "message": "內建", "description": "Filter lists section name" }, "3pGroupAds": { @@ -492,7 +492,7 @@ "description": "Filter lists section name" }, "3pGroupAnnoyances": { - "message": "嫌惡元素", + "message": "騷擾", "description": "Filter lists section name" }, "3pGroupMultipurpose": { @@ -512,7 +512,7 @@ "description": "The label for the checkbox used to import external filter lists" }, "3pExternalListsHint": { - "message": "每行一個網址。無效的網址將被忽略。", + "message": "每行一個網址。以「!」開頭的行將被忽略。無效的網址也將被忽略。", "description": "Short information about how to use the textarea to import external filter lists by URL" }, "3pExternalListObsolete": { @@ -524,7 +524,7 @@ "description": "used as a tooltip for eye icon beside a list" }, "3pLastUpdate": { - "message": "上次更新:{{ago}}。\n點擊此處以強制更新。", + "message": "最後更新:{{ago}}。", "description": "used as a tooltip for the clock icon beside a list" }, "3pUpdating": { @@ -536,11 +536,11 @@ "description": "used as a tooltip for error icon beside a list" }, "1pTrustWarning": { - "message": "切勿添加來歷不明的過濾規則。", + "message": "切勿添加來自不可信來源的過濾規則。", "description": "Warning against copy-pasting filters from random sources" }, "1pEnableMyFiltersLabel": { - "message": "啟用自訂過濾器", + "message": "啟用我的自訂過濾規則", "description": "Label for the checkbox use to enable/disable 'My filters' list" }, "1pTrustMyFiltersLabel": { @@ -624,7 +624,7 @@ "description": "English: a sort option for list of rules." }, "rulesSortByDestination": { - "message": "目標", + "message": "目的地", "description": "English: a sort option for list of rules." }, "whitelistPrompt": { @@ -760,15 +760,15 @@ "description": "Label to identify a rule field" }, "loggerEntryDetailsContext": { - "message": "上下文", + "message": "來源", "description": "Label to identify a context field (typically a hostname)" }, "loggerEntryDetailsRootContext": { - "message": "根上下文", + "message": "主內容", "description": "Label to identify a root context field (typically a hostname)" }, "loggerEntryDetailsPartyness": { - "message": "第一方/第三方", + "message": "第一方/第三方", "description": "Label to identify a field providing partyness information" }, "loggerEntryDetailsType": { @@ -832,15 +832,15 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringFinderSentence1": { - "message": "在下列清單中找到靜態過濾規則 {{filter}}:", + "message": "在下列清單中找到靜態過濾規則 {{filter}}:", "description": "Below this sentence, the filter list(s) in which the filter was found" }, "loggerStaticFilteringFinderSentence2": { - "message": "無法在任何目前已啟用的過濾規則清單中找到靜態過濾規則", + "message": "無法在任何啟用的過濾清單中,找到靜態過濾規則 {{filter}}", "description": "Message to show when a filter cannot be found in any filter lists" }, "loggerSettingDiscardPrompt": { - "message": "未符合以下所有條件的記錄將會被自動捨棄:", + "message": "不符合以下任一狀況的記錄將會被自動清除:", "description": "Logger setting: A sentence to describe the purpose of the settings below" }, "loggerSettingPerEntryMaxAge": { @@ -848,7 +848,7 @@ "description": "A logger setting" }, "loggerSettingPerTabMaxLoads": { - "message": "每個分頁最多保留 {{input}} 次重新載入該頁所產生的記錄", + "message": "每個分頁最多保留 {{input}} 次內容加載產生的記錄", "description": "A logger setting" }, "loggerSettingPerTabMaxEntries": { @@ -856,7 +856,7 @@ "description": "A logger setting" }, "loggerSettingPerEntryLineCount": { - "message": "在垂直延展模式中每條記錄顯示 {{input}} 行", + "message": "在垂直延展的模式中每個項目顯示 {{input}} 行", "description": "A logger setting" }, "loggerSettingHideColumnsPrompt": { @@ -900,7 +900,7 @@ "description": "Text for button which open an external webpage in Support pane" }, "supportReportSpecificButton": { - "message": "建立新報告", + "message": "發出新報告", "description": "Text for button which open an external webpage in Support pane" }, "supportFindSpecificButton": { @@ -924,7 +924,7 @@ "description": "First paragraph of 'Questions and support' section in Support pane" }, "supportS3H": { - "message": "過濾器問題 / 網站被破壞", + "message": "過濾器問題 / 網站被搞壞", "description": "Header of 'Filter issues' section in Support pane" }, "supportS3P1": { @@ -936,11 +936,11 @@ "description": "Second paragraph of 'Filter issues' section in Support pane" }, "supportS3P3": { - "message": "小提示:請確定您的過濾器清單已經更新至最新版本。我們主要用「記錄器」來分析過濾器相關問題。", + "message": "小提示:請確定您的過濾器清單已經更新至最新版本。我們主要用 記錄器 來分析過濾器相關問題。", "description": "Third paragraph of 'Filter issues' section in Support pane" }, "supportS4H": { - "message": "錯誤報告", + "message": "錯誤回報", "description": "Header of 'Bug report' section in Support pane" }, "supportS4P1": { @@ -964,11 +964,11 @@ "description": "Header of 'Report a filter issue' section in Support pane" }, "supportS6P1S1": { - "message": "為免給志願者帶來額外負擔,請先檢查問題有沒有被回報過,避免重複回報。", + "message": "為了避免太多人發出重複的報告拖垮志工,請先確認是否已經有人回報過您打算報告的問題。", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S1": { - "message": "過濾器清單每天更新,請確保問題尚未在最新版本中解決。", + "message": "過濾器清單每天更新。請確認您的問題無法用最新的過濾器清單解決。", "description": "A paragraph in the filter issue reporter section" }, "supportS6P2S2": { @@ -992,25 +992,29 @@ "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option2": { - "message": "含有覆蓋物或其他滋擾", + "message": "會覆蓋內容或有其他煩人的內容", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option3": { - "message": "偵測到 uBlock Origin", + "message": "會偵測到您已安裝 uBlock Origin", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option4": { - "message": "有私穩相關問題", + "message": "有隱私權相關問題", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option5": { - "message": "開啟 uBlock Origin 的時候運作不正常", + "message": "開啟 uBlock Origin 的時候網頁運作不正常", "description": "An entry in the widget used to select the type of issue" }, "supportS6Select1Option6": { "message": "會開啟不想要的分頁或視窗", "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" @@ -1052,11 +1056,11 @@ "description": "Link text to uBO's own filter lists repo" }, "aboutDependencies": { - "message": "外部相依套件(與 GPLv3 相容):", + "message": "外部相依套件(與通用公眾授權條款第三版相容):", "description": "Shown in the About pane" }, "aboutCDNs": { - "message": "uBO 自家的過濾規則清單由下列 CDN 免費代管:", + "message": "uBO 自家的過濾規則清單代管於下列 CDN 中:", "description": "Shown in the About pane" }, "aboutCDNsInfo": { @@ -1092,7 +1096,7 @@ "description": "Message asking user to confirm reset" }, "errorCantConnectTo": { - "message": "網路錯誤:{{msg}}", + "message": "無法連線至 {{url}}", "description": "English: Network error: {{msg}}" }, "subscriberConfirm": { @@ -1187,6 +1191,26 @@ "message": "繼續載入", "description": "Button text to navigate to the blocked page" }, + "docblockedRedirectPrompt": { + "message": "被封鎖的網頁想要重新導向至其他網站。如果您選擇繼續,則會直接前往:{{url}}", + "description": "Text warning about an incoming redirect" + }, + "docblockedReasonLabel": { + "message": "理由:", + "description": "The label which prepend the actual reason why a page was blocked" + }, + "docblockedReasonMalicious": { + "message": "惡意程式碼", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonTracker": { + "message": "追蹤器", + "description": "An actual reason why a page was blocked" + }, + "docblockedReasonDisreputable": { + "message": "聲名狼藉", + "description": "An actual reason why a page was blocked" + }, "cloudPush": { "message": "匯出至雲端儲存空間", "description": "tooltip" @@ -1208,7 +1232,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": { @@ -1232,7 +1256,7 @@ "description": "An entry in the browser's contextual menu" }, "contextMenuSubscribeToList": { - "message": "訂閱過濾規則清單…", + "message": "訂閱過濾器清單⋯", "description": "An entry in the browser's contextual menu" }, "contextMenuTemporarilyAllowLargeMediaElements": { @@ -1240,11 +1264,11 @@ "description": "A context menu entry, present when large media elements have been blocked on the current site" }, "contextMenuViewSource": { - "message": "檢視源碼…", + "message": "檢視原始碼…", "description": "A context menu entry, to view the source code of the target resource" }, "shortcutCapturePlaceholder": { - "message": "輸入快捷鍵", + "message": "鍵入快速鍵", "description": "Placeholder string for input field used to capture a keyboard shortcut" }, "genericMergeViewScrollLock": { @@ -1296,7 +1320,7 @@ "description": "Summary of number of errors as reported by the linter " }, "unprocessedRequestTooltip": { - "message": "無法在瀏覽器啟動的時候正確過濾頁面。請重新載入來確保過濾正確。", + "message": "無法在瀏覽器啟動的時候正確過濾。\n請重新載入頁面來確保過濾正確。", "description": "A warning which will appear in the popup panel if needed" }, "dummy": { diff --git a/src/about.html b/src/about.html index fc98984178b23..e747a93051d2a 100644 --- a/src/about.html +++ b/src/about.html @@ -3,6 +3,7 @@ + uBlock — About diff --git a/src/advanced-settings.html b/src/advanced-settings.html index 22bee72db1207..b55bdbad6cf58 100644 --- a/src/advanced-settings.html +++ b/src/advanced-settings.html @@ -3,6 +3,7 @@ + @@ -13,7 +14,7 @@ - + diff --git a/src/asset-viewer.html b/src/asset-viewer.html index b30320f9e523e..5cfc73ebe06e8 100644 --- a/src/asset-viewer.html +++ b/src/asset-viewer.html @@ -3,6 +3,7 @@ + @@ -11,7 +12,7 @@ - + diff --git a/src/blank.html b/src/blank.html new file mode 100644 index 0000000000000..be329a5cc9426 --- /dev/null +++ b/src/blank.html @@ -0,0 +1,11 @@ + + + + + + +uBO blank + + + + diff --git a/src/code-viewer.html b/src/code-viewer.html index 4b699feda925d..caddbdaab87f4 100644 --- a/src/code-viewer.html +++ b/src/code-viewer.html @@ -3,6 +3,7 @@ + Code viewer diff --git a/src/css/codemirror.css b/src/css/codemirror.css index 9036acc990182..d56d8c0da1a13 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); @@ -352,3 +356,9 @@ html:not(.mobile) .cm-search-widget .fa-icon:not(.fa-icon-ro):hover { .CodeMirror-lintmarker[data-error="y"] > span:hover { display: initial; } + +/* https://github.com/uBlockOrigin/uBlock-issues/issues/3645 */ +.CodeMirror-vscrollbar { + pointer-events: initial !important; + } + diff --git a/src/css/common.css b/src/css/common.css index fae4bb5d6205e..42b196dfd25a6 100644 --- a/src/css/common.css +++ b/src/css/common.css @@ -37,6 +37,7 @@ --default-gap-small: 12px; --default-gap-xsmall: 8px; --default-gap-xxsmall: 4px; + --button-font-size: max(calc(var(--font-size) * 0.875), 14px); } /* Common uBO styles */ @@ -85,7 +86,7 @@ button { color: var(--button-ink); display: inline-flex; fill: var(--button-ink); - font-size: max(calc(var(--font-size) * 0.875), 14px); + font-size: var(--button-font-size); justify-content: center; min-height: 36px; padding: 0 var(--font-size); diff --git a/src/css/dashboard.css b/src/css/dashboard.css index 20b35e57cc416..bff9fa15922f8 100644 --- a/src/css/dashboard.css +++ b/src/css/dashboard.css @@ -1,4 +1,5 @@ html, body { + background-color: var(--surface-0); display: flex; flex-direction: column; height: 100vh; @@ -13,6 +14,7 @@ body.notReady { } #dashboard-nav { align-items: center; + background-color: var(--surface-1); border: 0; border-bottom: 1px solid var(--border-1); display: flex; diff --git a/src/css/document-blocked.css b/src/css/document-blocked.css index 62d49216a5b03..169acf9d6f507 100644 --- a/src/css/document-blocked.css +++ b/src/css/document-blocked.css @@ -23,17 +23,26 @@ body { padding: var(--default-gap-xxlarge) var(--default-gap-small); justify-content: center; } +body.loading { + opacity: 0; + } :root.mobile body { padding: var(--default-gap-small); } #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 +54,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 +71,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%; @@ -110,15 +131,27 @@ body[dir="rtl"] #toggleParse { font-weight: bold; } -#whyex a { +.why-extra a { white-space: nowrap; } -#whyex ul { +.why-extra ul { display: flex; flex-direction: column; margin: 0; padding-inline-start: var(--default-gap-xsmall); } +details > *:not(summary) { + margin-inline-start: 1em; + } + +#urlskip a { + display: block; + overflow-y: auto; + word-break: break-all; + } +:root.mobile #urlskip a { + max-height: 3lh; + } #actionContainer { display: flex; @@ -134,11 +167,14 @@ body[dir="rtl"] #toggleParse { } .filterList { - display: flex; -} -.filterList .filterListSupport[href=""] { + white-space: nowrap; + } +.filterList .filterListSupport[href="#"] { display: none; } +.filterList .filterListSupport:not([href="#"]) { + margin-inline-start: 0.25em; + } /* Small-screen devices */ :root.mobile button { diff --git a/src/css/epicker-ui.css b/src/css/epicker-ui.css index 1923142b2f7d5..a8aa13908526d 100644 --- a/src/css/epicker-ui.css +++ b/src/css/epicker-ui.css @@ -1,3 +1,7 @@ +:root { + --quit-button-size: max(4em, min(6em, calc(100vw / 8), calc(100vh / 8))); +} + html#ublock0-epicker, #ublock0-epicker body { background: transparent; @@ -16,7 +20,7 @@ html#ublock0-epicker, border: 1px solid var(--border-2); box-sizing: border-box; cursor: default; - display: none; + display: flex; flex-direction: column; max-width: min(32rem, 100vw - 4px); min-width: min(24rem, 100vw - 4px); @@ -25,8 +29,21 @@ html#ublock0-epicker, width: min(32rem, 100vw - 4px); z-index: 100; } -#ublock0-epicker:not(.zap) aside { - display: flex; +#ublock0-epicker.zap aside { + bottom: unset !important; + min-width: unset !important; + top: 50%; + transform: translateY(-50%); + width: unset !important; +} +#ublock0-epicker.zap aside > section, +#ublock0-epicker.zap aside > ul, +#ublock0-epicker.zap aside > #windowbar > div:not(#quit) { + display: none; +} +#ublock0-epicker.zap aside > #windowbar > #quit { + width: var(--quit-button-size); + height: var(--quit-button-size); } #ublock0-epicker:not(.paused) aside, #ublock0-epicker.minimized aside { diff --git a/src/css/fonts/Inter/Inter-Regular.woff2 b/src/css/fonts/Inter/Inter-Regular.woff2 index d5ffd2a1f1306..2bcd222ecfae9 100644 Binary files a/src/css/fonts/Inter/Inter-Regular.woff2 and b/src/css/fonts/Inter/Inter-Regular.woff2 differ diff --git a/src/css/fonts/Inter/Inter-SemiBold.woff2 b/src/css/fonts/Inter/Inter-SemiBold.woff2 index df746af9991a3..fbae113d2855e 100644 Binary files a/src/css/fonts/Inter/Inter-SemiBold.woff2 and b/src/css/fonts/Inter/Inter-SemiBold.woff2 differ diff --git a/src/css/themes/default.css b/src/css/themes/default.css index c37bd28f02a2b..28b592f62a477 100644 --- a/src/css/themes/default.css +++ b/src/css/themes/default.css @@ -381,10 +381,8 @@ --logger-scriptlet-surface: rgb(var(--yellow-30) / 40%); } -:root.dark input, -:root.dark select, -:root.dark textarea { - color-scheme: dark; +:root.dark { + color-scheme: dark light; } /* @@ -455,7 +453,7 @@ --popup-cell-block-surface: rgb(var(--popup-cell-block-surface-rgb)); --popup-power-ink: rgb(var(--popup-power-ink-rgb)); --popup-toolbar-surface: rgb(var(--primary-80) / 15%); - --popup-toolbar-surface-hover: rgb(var(--primary-80) / 20%); + --popup-toolbar-surface-hover: rgb(var(--primary-80) / 30%); --popup-ruleset-tool-ink: var(--ink-1); --popup-ruleset-tool-surface: rgb(var(--primary-80) / 15%); --popup-ruleset-tool-surface-hover: rgb(var(--primary-80) / 20%); diff --git a/src/dashboard.html b/src/dashboard.html index b62813be838ca..1d401c19fc7c1 100644 --- a/src/dashboard.html +++ b/src/dashboard.html @@ -3,12 +3,13 @@ + - + @@ -36,7 +37,7 @@

- + diff --git a/src/devtools.html b/src/devtools.html index 8f66827bfaca8..8893759d92e60 100644 --- a/src/devtools.html +++ b/src/devtools.html @@ -3,6 +3,7 @@ + uBlock — Dev tools @@ -33,7 +34,7 @@ -
+
diff --git a/src/document-blocked.html b/src/document-blocked.html index 80a45461afd7f..1fb3876729c1d 100644 --- a/src/document-blocked.html +++ b/src/document-blocked.html @@ -3,14 +3,15 @@ + - + - +
exclamation-triangle @@ -24,13 +25,9 @@
-
-

_

-

 

- +
+ +
@@ -42,14 +39,29 @@
+
-