diff --git a/assets/assets.json b/assets/assets.json index af187d02a46ae..a8e4aaa479cac 100644 --- a/assets/assets.json +++ b/assets/assets.json @@ -216,7 +216,7 @@ "group": "social", "off": true, "title": "Anti-Facebook", - "contentURL": "https://fanboy.co.nz/fanboy-antifacebook.txt", + "contentURL": "https://secure.fanboy.co.nz/fanboy-antifacebook.txt", "supportURL": "https://github.com/ryanbr/fanboy-adblock/issues" }, "fanboy-annoyance": { @@ -224,10 +224,7 @@ "group": "social", "off": true, "title": "Fanboy’s Annoyance", - "contentURL": [ - "https://easylist.to/easylist/fanboy-annoyance.txt", - "https://fanboy.co.nz/fanboy-annoyance.txt" - ], + "contentURL": "https://secure.fanboy.co.nz/fanboy-annoyance.txt", "supportURL": "https://forums.lanik.us/" }, "fanboy-cookiemonster": { @@ -235,7 +232,7 @@ "group": "social", "off": true, "title": "EasyList Cookie", - "contentURL": "https://easylist-downloads.adblockplus.org/easylist-cookie.txt", + "contentURL": "https://secure.fanboy.co.nz/fanboy-cookiemonster.txt", "supportURL": "https://github.com/easylist/easylist/issues" }, "fanboy-social": { @@ -245,7 +242,7 @@ "title": "Fanboy’s Social", "contentURL": [ "https://easylist.to/easylist/fanboy-social.txt", - "https://fanboy.co.nz/fanboy-social.txt" + "https://secure.fanboy.co.nz/fanboy-social.txt" ], "supportURL": "https://forums.lanik.us/" }, diff --git a/assets/resources/scriptlets.js b/assets/resources/scriptlets.js index 5152c3d491e75..7875ec4617190 100644 --- a/assets/resources/scriptlets.js +++ b/assets/resources/scriptlets.js @@ -433,21 +433,28 @@ } return true; }; + const pruner = function(o) { + if ( log !== undefined ) { + const json = JSON.stringify(o, null, 2); + if ( reLogNeedle.test(json) ) { + log('uBO:', location.hostname, json); + } + return o; + } + if ( mustProcess(o) === false ) { return o; } + for ( const path of prunePaths ) { + findOwner(o, path, true); + } + return o; + }; JSON.parse = new Proxy(JSON.parse, { apply: function() { - const r = Reflect.apply(...arguments); - if ( log !== undefined ) { - const json = JSON.stringify(r, null, 2); - if ( reLogNeedle.test(json) ) { - log('uBO:', location.hostname, json); - } - return r; - } - if ( mustProcess(r) === false ) { return r; } - for ( const path of prunePaths ) { - findOwner(r, path, true); - } - return r; + return pruner(Reflect.apply(...arguments)); + }, + }); + Response.prototype.json = new Proxy(Response.prototype.json, { + apply: function() { + return Reflect.apply(...arguments).then(o => pruner(o)); }, }); })(); diff --git a/dist/description/description-de.txt b/dist/description/description-de.txt index 6ee8b523c1212..7d9fa2b478c5a 100644 --- a/dist/description/description-de.txt +++ b/dist/description/description-de.txt @@ -1,4 +1,4 @@ -Ein effizienter Blocker: Geringer Speicherbedarf und niedrige CPU-Belastung - und dennoch werden Tausende an Filtern mehr angewendet als bei anderen populären Blockern. +Ein effizienter Blocker: Geringer Speicherbedarf und niedrige CPU-Belastung - und dennoch werden tausende Filter mehr angewendet als bei anderen beliebten Blockern. Ein illustrierter Überblick über seine Effizienz: https://github.com/gorhill/uBlock/wiki/uBlock-vs.-ABP:-efficiency-compared @@ -30,7 +30,7 @@ Bedenke allerdings, dass durch die Wahl zusätzlicher Listen die Wahrscheinlichk - Wenn du etwas beitragen möchtest, dann denke an die Menschen, die hart dafür arbeiten, die von dir benutzten Filterlisten zu pflegen, und diese für uns alle frei verfügbar gemacht haben. + Wenn du etwas beitragen möchtest, dann denke an die Menschen, die hart dafür arbeiten, die von dir benutzten Filterlisten zu pflegen und diese für uns alle frei verfügbar gemacht haben. diff --git a/dist/description/description-ml.txt b/dist/description/description-ml.txt index 10ad6432e273c..029603755c22e 100644 --- a/dist/description/description-ml.txt +++ b/dist/description/description-ml.txt @@ -24,17 +24,17 @@ -സ്പാം404 -കൂടാതെ മറ്റ് അനവധി -തീര്‍ച്ചയായും, കൂടുതല്‍ ഫില്‍ട്ടറുകള്‍ എനേബിള്‍ ചെയ്യുംതോറും മെമ്മറി ഉപഭോഗം കൂടുന്നതാണ്. Yet, even after adding Fanboy's two extra lists, hpHosts’s Ad and tracking servers, uBlock still has a lower memory footprint than other very popular blockers out there. +തീര്‍ച്ചയായും, കൂടുതല്‍ ഫില്‍ട്ടറുകള്‍ എനേബിള്‍ ചെയ്യുംതോറും മെമ്മറി ഉപഭോഗം കൂടുന്നതാണ്. എന്നിട്ടും, ഫാൻ‌ബോയിയുടെ രണ്ട് അധിക ലിസ്റ്റുകളായ എച്ച്പി ഹോസ്റ്റുകളുടെ പരസ്യവും ട്രാക്കിംഗ് സെർ‌വറുകളും ചേർ‌ത്തിട്ടും, യു‌ബ്ലോക്കിന് അവിടെയുള്ള മറ്റ് ജനപ്രിയ ബ്ലോക്കറുകളേക്കാൾ കുറഞ്ഞ മെമ്മറി കാൽ‌നോട്ടമുണ്ട്. -Also, be aware that selecting some of these extra lists may lead to higher likelihood of web site breakage -- especially those lists which are normally used as hosts file. +കൂടാതെ, ഈ അധിക ലിസ്റ്റുകളിൽ ചിലത് തിരഞ്ഞെടുക്കുന്നത് വെബ് സൈറ്റ് തകരാനുള്ള സാധ്യതയിലേക്ക് നയിച്ചേക്കാം - പ്രത്യേകിച്ചും ഹോസ്റ്റ് ഫയലായി സാധാരണയായി ഉപയോഗിക്കുന്ന ലിസ്റ്റുകൾ. *** -Without the preset lists of filters, this extension is nothing. So if ever you really do want to contribute something, think about the people working hard to maintain the filter lists you are using, which were made available to use by all for free. +ഫിൽട്ടറുകളുടെ പ്രീസെറ്റ് ലിസ്റ്റുകൾ ഇല്ലാതെ, ഈ വിപുലീകരണം ഒന്നുമല്ല. അതിനാൽ നിങ്ങൾ എപ്പോഴെങ്കിലും എന്തെങ്കിലും സംഭാവന ചെയ്യാൻ ആഗ്രഹിക്കുന്നുവെങ്കിൽ, നിങ്ങൾ ഉപയോഗിക്കുന്ന ഫിൽട്ടർ ലിസ്റ്റുകൾ പരിപാലിക്കാൻ കഠിനമായി പരിശ്രമിക്കുന്ന ആളുകളെക്കുറിച്ച് ചിന്തിക്കുക, അവ എല്ലാവർക്കും സ use ജന്യമായി ഉപയോഗിക്കാൻ ലഭ്യമാക്കി. *** -Free. +സൗ ജന്യം ഓപ്പണ്‍‌സോഴ്സ് പബ്ലിക്‌ ലൈസന്‍സ് (ജിപിഎല്‍വി3) ഉഭയോക്താക്കള്‍ക്ക്‌ ഉഭയോക്താക്കളില്‍ നിന്നും. diff --git a/dist/description/description-ta.txt b/dist/description/description-ta.txt new file mode 100644 index 0000000000000..a150b3ec5f3ad --- /dev/null +++ b/dist/description/description-ta.txt @@ -0,0 +1,52 @@ +ஒரு திறமையான தடுப்பான்: நினைவகம் மற்றும் CPU தடம் எளிதானது, ஆனால் அங்குள்ள பிற பிரபலமான தடுப்பான்களைக் காட்டிலும் ஆயிரக்கணக்கான வடிப்பான்களை ஏற்றலாம் மற்றும் செயல்படுத்தலாம். + +அதன் செயல்திறனைப் பற்றிய விளக்கமான கண்ணோட்டம்: https://github.com/gorhill/uBlock/wiki/uBlock-vs.-ABP:-efficiency-compared + +பயன்பாடு: தற்போதைய வலைத்தளத்திற்கான uBlock ஐ நிரந்தரமாக முடக்க / இயக்குவதே பாப்அப்பில் உள்ள பெரிய ஆற்றல் பொத்தான். இது தற்போதைய வலைத்தளத்திற்கு மட்டுமே பொருந்தும், இது உலகளாவிய சக்தி பொத்தான் அல்ல. + +*** + +நெகிழ்வான, இது ஒரு "விளம்பரத் தடுப்பான்" ஐ விட அதிகம்: இது ஹோஸ்ட் கோப்புகளிலிருந்து வடிப்பான்களைப் படித்து உருவாக்கலாம். + +பெட்டியின் வெளியே, இந்த வடிப்பான்களின் பட்டியல்கள் ஏற்றப்பட்டு செயல்படுத்தப்படுகின்றன: + +- EasyList + +- Peter Lowe’s Ad server list + +- EasyPrivacy + +- தீம்பொருள் களங்கள் + +நீங்கள் விரும்பினால் தேர்ந்தெடுக்க கூடுதல் பட்டியல்கள் கிடைக்கின்றன: + +- ஃபான்பாயின் மேம்படுத்தப்பட்ட கண்காணிப்பு பட்டியல் +- டான் பொல்லாக் ஹோஸ்ட்கள் கோப்பு +- hpHosts இன் விளம்பரம் மற்றும் கண்காணிப்பு சேவையகங்கள் +- எம்விபிஎஸ் ஹோஸ்ட்ஸ் +- ஸ்பேம் 404 +- மற்றும் பலர் + +நிச்சயமாக, அதிகமான வடிப்பான்கள் இயக்கப்பட்டன, நினைவக தடம் அதிகமாகும். இருப்பினும், ஃபான்பாயின் இரண்டு கூடுதல் பட்டியல்களான hpHosts இன் விளம்பரம் மற்றும் கண்காணிப்பு சேவையகங்களைச் சேர்த்த பிறகும், uBlock இன்னும் பிரபலமான பிற தடுப்பான்களைக் காட்டிலும் குறைந்த நினைவக தடம் உள்ளது. + +மேலும், இந்த கூடுதல் பட்டியல்களில் சிலவற்றைத் தேர்ந்தெடுப்பது வலைத்தள உடைப்புக்கான அதிக வாய்ப்புக்கு வழிவகுக்கும் என்பதை அறிந்து கொள்ளுங்கள் - குறிப்பாக அந்த பட்டியல்கள் பொதுவாக ஹோஸ்ட்கள் கோப்பாகப் பயன்படுத்தப்படுகின்றன. + +*** + +வடிப்பான்களின் முன்னமைக்கப்பட்ட பட்டியல்கள் இல்லாமல், இந்த நீட்டிப்பு எதுவும் இல்லை. ஆகவே, நீங்கள் உண்மையிலேயே ஏதாவது பங்களிக்க விரும்பினால், நீங்கள் பயன்படுத்தும் வடிகட்டி பட்டியல்களைப் பராமரிக்க கடினமாக உழைக்கும் நபர்களைப் பற்றி சிந்தியுங்கள், அவை அனைவருக்கும் இலவசமாகப் பயன்படுத்தக் கிடைத்தன. + +*** + +இலவசம். +பொது உரிமத்துடன் திறந்த மூல (GPLv3) +பயனர்களால் பயனர்களுக்கு. + +பங்களிப்பாளர்கள் @ கிதுப்: https://github.com/gorhill/uBlock/graphs/contributors +பங்களிப்பாளர்கள் @ க்ரவுடின்: https://crowdin.net/project/ublock + +*** + +It's quite an early version, keep this in mind when you review. + +திட்ட மாற்ற பதிவு: +https://github.com/gorhill/uBlock/releases diff --git a/dist/firefox/updates.json b/dist/firefox/updates.json index c8c5b5599b1bd..54b84a5826354 100644 --- a/dist/firefox/updates.json +++ b/dist/firefox/updates.json @@ -3,10 +3,10 @@ "uBlock0@raymondhill.net": { "updates": [ { - "version": "1.29.3.112", + "version": "1.30.11.100", "browser_specific_settings": { "gecko": { "strict_min_version": "55" } }, - "update_info_url": "https://github.com/gorhill/uBlock/releases/tag/1.29.3rc12", - "update_link": "https://github.com/gorhill/uBlock/releases/download/1.29.3rc12/uBlock0_1.29.3rc12.firefox.signed.xpi" + "update_info_url": "https://github.com/gorhill/uBlock/releases/tag/1.30.11rc0", + "update_link": "https://github.com/gorhill/uBlock/releases/download/1.30.11rc0/uBlock0_1.30.11rc0.firefox.signed.xpi" } ] } diff --git a/dist/version b/dist/version index 2e0949ed3934a..34aae156b1929 100644 --- a/dist/version +++ b/dist/version @@ -1 +1 @@ -1.30.10 +1.31.0 diff --git a/docs/tests/static-filtering-parser-checklist.txt b/docs/tests/static-filtering-parser-checklist.txt index 3506116738c0d..c88599983d854 100644 --- a/docs/tests/static-filtering-parser-checklist.txt +++ b/docs/tests/static-filtering-parser-checklist.txt @@ -44,7 +44,6 @@ a* $script,redirect=noop.js *$empty *$xhr,empty -*$redirect=empty *$xhr,redirect=empty *$csp=default-src 'none' @@ -58,7 +57,7 @@ $script,redirect=noop.js *$domain=toto.com|toto.*|~toto.com|~toto.*|tôtó.ça|tôtó.*|~tôtó.ça|[ff00::0]|1.1.1.1 ! valid denyallow option values -*$denyallow=toto.com|tôtó.ça|[ff00::0]|1.1.1.1 +*$denyallow=toto.com|tôtó.ça|[ff00::0]|1.1.1.1,domain=toto.com @@ -95,10 +94,11 @@ $ ! can't redirect without type (except to `empty`) *$redirect=noop.js -! can't redirect beacon, ping, websocket +! non-redirectable types *$beacon,redirect-rule=empty *$ping,redirect-rule=empty *$websocket,redirect-rule=empty +*$ghide,redirect=noop.js ! can't mix csp with other types or redirect directives *$csp=default-src 'none',empty @@ -119,4 +119,7 @@ $ *$domain=.toto.com|toto.com.|[ff00::00000]|1.1.1.1111 ! invalid denyallow= option values -*$denyallow=.toto.com|toto.com.|toto.*|~toto.com|~toto.*|[ff00::00000]|1.1.1.1111 +*$denyallow=.toto.com|toto.com.|toto.*|~toto.com|~toto.*|[ff00::00000]|1.1.1.1111,domain=toto.com + +! denyallow= requires a domain= option +*$script,denyallow=toto.com diff --git a/platform/chromium/vapi-background.js b/platform/chromium/vapi-background.js index 7df03e81e2a6d..8f7b3d0cd61c6 100644 --- a/platform/chromium/vapi-background.js +++ b/platform/chromium/vapi-background.js @@ -902,17 +902,28 @@ vAPI.messaging = { this.ports.delete(port.name); }, + // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/Port + // port.sender is always present for onConnect() listeners. onPortConnect: function(port) { - port.onDisconnect.addListener( - port => this.onPortDisconnect(port) + port.onDisconnect.addListener(port => + this.onPortDisconnect(port) ); - port.onMessage.addListener( - (request, port) => this.onPortMessage(request, port) + port.onMessage.addListener((request, port) => + this.onPortMessage(request, port) ); - this.ports.set(port.name, { - port, - privileged: port.sender.url.startsWith(this.PRIVILEGED_URL) - }); + const portDetails = { port }; + const sender = port.sender; + const { tab, url } = sender; + portDetails.frameId = sender.frameId; + portDetails.frameURL = url; + portDetails.privileged = url.startsWith(this.PRIVILEGED_URL); + if ( tab ) { + portDetails.tabId = tab.id; + portDetails.tabURL = tab.url; + } + this.ports.set(port.name, portDetails); + // https://bugzilla.mozilla.org/show_bug.cgi?id=1652925#c24 + port.sender = undefined; }, setup: function(defaultHandler) { @@ -936,12 +947,9 @@ vAPI.messaging = { vAPI.webextFlavor.major < 61 ) { browser.tabs.onRemoved.addListener(tabId => { - for ( const { port } of this.ports.values() ) { - const tab = port.sender && port.sender.tab; - if ( !tab ) { continue; } - if ( tab.id === tabId ) { - this.onPortDisconnect(port); - } + for ( const { port, tabId: portTabId } of this.ports.values() ) { + if ( portTabId !== tabId ) { continue; } + this.onPortDisconnect(port); } }); } @@ -963,10 +971,8 @@ vAPI.messaging = { }, onFrameworkMessage: function(request, port, callback) { - const sender = port && port.sender; - if ( !sender ) { return; } - const fromDetails = this.ports.get(port.name) || {}; - const tabId = sender.tab && sender.tab.id || undefined; + const portDetails = this.ports.get(port.name) || {}; + const tabId = portDetails.tabId; const msg = request.msg; switch ( msg.what ) { case 'connectionAccepted': @@ -1011,7 +1017,7 @@ vAPI.messaging = { }); break; case 'localStorage': { - if ( fromDetails.privileged !== true ) { break; } + if ( portDetails.privileged !== true ) { break; } const args = msg.args || []; vAPI.localStorage[msg.fn](...args).then(result => { callback(result); @@ -1022,7 +1028,7 @@ vAPI.messaging = { if ( tabId === undefined ) { break; } const details = { code: undefined, - frameId: sender.frameId, + frameId: portDetails.frameId, matchAboutBlank: true }; if ( msg.add ) { @@ -1033,11 +1039,9 @@ vAPI.messaging = { details.code = cssText; promises.push(vAPI.tabs.insertCSS(tabId, details)); } - if ( typeof webext.tabs.removeCSS === 'function' ) { - for ( const cssText of msg.remove ) { - details.code = cssText; - promises.push(vAPI.tabs.removeCSS(tabId, details)); - } + for ( const cssText of msg.remove ) { + details.code = cssText; + promises.push(vAPI.tabs.removeCSS(tabId, details)); } Promise.all(promises).then(( ) => { callback(); @@ -1094,23 +1098,23 @@ vAPI.messaging = { } // Auxiliary process to main process: specific handler - const fromDetails = this.ports.get(port.name); - if ( fromDetails === undefined ) { return; } + const portDetails = this.ports.get(port.name); + if ( portDetails === undefined ) { return; } const listenerDetails = this.listeners.get(request.channel); let r = this.UNHANDLED; if ( (listenerDetails !== undefined) && - (listenerDetails.privileged === false || fromDetails.privileged) - + (listenerDetails.privileged === false || portDetails.privileged) + ) { - r = listenerDetails.fn(request.msg, port.sender, callback); + r = listenerDetails.fn(request.msg, portDetails, callback); } if ( r !== this.UNHANDLED ) { return; } // Auxiliary process to main process: default handler - if ( fromDetails.privileged ) { - r = this.defaultHandler(request.msg, port.sender, callback); + if ( portDetails.privileged ) { + r = this.defaultHandler(request.msg, portDetails, callback); if ( r !== this.UNHANDLED ) { return; } } @@ -1153,7 +1157,7 @@ vAPI.warSecret = (( ) => { url.lastIndexOf(`?secret=${secret}`) !== -1 ); if ( pos === -1 ) { - return { redirectUrl: root }; + return { cancel: true }; } secrets.splice(pos, 1); }; @@ -1177,7 +1181,7 @@ vAPI.warSecret = (( ) => { lastSecretTime = Date.now(); const secret = generateSecret(); secrets.push(secret); - return `?secret=${secret}`; + return secret; }; })(); @@ -1518,27 +1522,10 @@ vAPI.localStorage = { if ( this.cache instanceof Promise ) { return this.cache; } if ( this.cache instanceof Object ) { return this.cache; } this.cache = webext.storage.local.get('localStorage').then(bin => { - this.cache = undefined; - try { - if ( - bin instanceof Object === false || - bin.localStorage instanceof Object === false - ) { - this.cache = {}; - const ls = self.localStorage; - for ( let i = 0; i < ls.length; i++ ) { - const key = ls.key(i); - this.cache[key] = ls.getItem(key); - } - webext.storage.local.set({ localStorage: this.cache }); - } else { - this.cache = bin.localStorage; - } - } catch(ex) { - } - if ( this.cache instanceof Object === false ) { - this.cache = {}; - } + this.cache = bin instanceof Object && + bin.localStorage instanceof Object + ? bin.localStorage + : {}; }); return this.cache; }, diff --git a/platform/chromium/webext.js b/platform/chromium/webext.js index fb391c0ecfa63..db7e7d4f9f21a 100644 --- a/platform/chromium/webext.js +++ b/platform/chromium/webext.js @@ -93,6 +93,7 @@ const webext = { get: promisifyNoFail(chrome.tabs, 'get', tab => tab instanceof Object ? tab : null), executeScript: promisifyNoFail(chrome.tabs, 'executeScript'), insertCSS: promisifyNoFail(chrome.tabs, 'insertCSS'), + removeCSS: promisifyNoFail(chrome.tabs, 'removeCSS'), query: promisifyNoFail(chrome.tabs, 'query', tabs => Array.isArray(tabs) ? tabs : []), reload: promisifyNoFail(chrome.tabs, 'reload'), remove: promisifyNoFail(chrome.tabs, 'remove'), diff --git a/platform/firefox/vapi-webrequest.js b/platform/firefox/vapi-webrequest.js index a7c14c24c79ab..eaa74b34f64fc 100644 --- a/platform/firefox/vapi-webrequest.js +++ b/platform/firefox/vapi-webrequest.js @@ -125,19 +125,21 @@ this.cnameFlushTime = Date.now() + this.cnameMaxTTL * 60000; // https://github.com/uBlockOrigin/uBlock-issues/issues/911 // Install/remove proxy detector. - const wrohr = browser.webRequest.onHeadersReceived; - if ( cnameUncloak === false || cnameUncloakProxied ) { - if ( wrohr.hasListener(proxyDetector) ) { - wrohr.removeListener(proxyDetector); + if ( vAPI.webextFlavor.major < 80 ) { + const wrohr = browser.webRequest.onHeadersReceived; + if ( cnameUncloak === false || cnameUncloakProxied ) { + if ( wrohr.hasListener(proxyDetector) ) { + wrohr.removeListener(proxyDetector); + } + } else if ( wrohr.hasListener(proxyDetector) === false ) { + wrohr.addListener( + proxyDetector, + { urls: [ '*://*/*' ] }, + [ 'blocking' ] + ); } - } else if ( wrohr.hasListener(proxyDetector) === false ) { - wrohr.addListener( - proxyDetector, - { urls: [ '*://*/*' ] }, - [ 'blocking' ] - ); + proxyDetectorTryCount = 32; } - proxyDetectorTryCount = 32; } normalizeDetails(details) { if ( mustPunycode && !reAsciiHostname.test(details.url) ) { diff --git a/src/1p-filters.html b/src/1p-filters.html index 2a6cb1ba0cb7f..4697097ec2611 100644 --- a/src/1p-filters.html +++ b/src/1p-filters.html @@ -25,7 +25,7 @@
-

+

diff --git a/src/_locales/ar/messages.json b/src/_locales/ar/messages.json index 530d2325545a9..cbb35bcc4d592 100644 --- a/src/_locales/ar/messages.json +++ b/src/_locales/ar/messages.json @@ -96,11 +96,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": { @@ -180,19 +180,19 @@ "description": "Tooltip for the no-scripting per-site switch" }, "popupNoPopups_v2": { - "message": "نافذة منبثقة", + "message": "الإطارات المنبثقة", "description": "Caption for the no-popups per-site switch" }, "popupNoLargeMedia_v2": { - "message": "وسائط ميديا كبيرة", + "message": "المرئيات الضخمة", "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": { - "message": "الخطوط البعيدة", + "message": "الخطوط الخارجية", "description": "Caption for the no-remote-fonts per-site switch" }, "popupNoScripting_v2": { @@ -552,19 +552,19 @@ "description": "English: dynamic rule syntax and full documentation." }, "rulesSort": { - "message": "Sort:", + "message": "الفرز", "description": "English: label for sort option." }, "rulesSortByType": { - "message": "Rule type", + "message": "الإشتراطات", "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": { @@ -648,7 +648,7 @@ "description": "Tooltip for the row filterer button in the logger page" }, "logFilterPrompt": { - "message": "فلتر سجل الإدخالات", + "message": "رشّح محتوى السجل", "description": "Placeholder string for logger output filtering input field" }, "loggerRowFiltererBuiltinTip": { @@ -671,6 +671,10 @@ "message": "السماح", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "الطرف الأول", "description": "A keyword in the built-in row filtering expression" @@ -908,7 +912,7 @@ "description": "No longer used" }, "subscribeButton": { - "message": "Subscribe", + "message": "اشترك", "description": "For the button used to subscribe to a filter list" }, "elapsedOneMinuteAgo": { @@ -1063,6 +1067,10 @@ "message": "جيغا بايت", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "اضغط للتحميل", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "يجب أن يكون هذا الإدخال آخر واحد", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/az/messages.json b/src/_locales/az/messages.json index 938b5c5b69a6e..f080fba822619 100644 --- a/src/_locales/az/messages.json +++ b/src/_locales/az/messages.json @@ -12,7 +12,7 @@ "description": "English: uBlock₀ — Dashboard" }, "dashboardUnsavedWarning": { - "message": "Diqqət! Yadda saxlamadığınız dəyişikliklər var", + "message": "Xəbərdarlıq! Saxlamadığınız dəyişikliklər var", "description": "A warning in the dashboard when navigating away from unsaved changes" }, "dashboardUnsavedWarningStay": { @@ -20,7 +20,7 @@ "description": "Label for button to prevent navigating away from unsaved changes" }, "dashboardUnsavedWarningIgnore": { - "message": "Nəzərə alma", + "message": "Əhəmiyyət vermə", "description": "Label for button to ignore unsaved changes" }, "settingsPageName": { @@ -40,7 +40,7 @@ "description": "appears as tab name in dashboard" }, "whitelistPageName": { - "message": "İstisnalar", + "message": "Etibarlı saytlar", "description": "appears as tab name in dashboard" }, "shortcutsPageName": { @@ -48,7 +48,7 @@ "description": "appears as tab name in dashboard" }, "statsPageName": { - "message": "uBlock₀ — Qeydiyyatçı", + "message": "uBlock₀ — Jurnal", "description": "Title for the logger window" }, "aboutPageName": { @@ -60,19 +60,19 @@ "description": "Title for the asset viewer page" }, "advancedSettingsPageName": { - "message": "Əlavə parametrlər", + "message": "Qabaqcıl tənzimləmələr", "description": "Title for the advanced settings page" }, "popupPowerSwitchInfo": { - "message": "Klik: Bu saytda uBlock₀-u işə sal/dayandır.\n\nCtrl+klik: Yalnız bu səhifədə uBlock₀-u dayandır.", + "message": "Klikləmə: Bu sayt üçün uBlock₀-u fəallaşdır/sıradan çıxart.\n\nCtrl+klikləmə: Yalnız bu səhifə üçün uBlock₀-u sıradan çıxart.", "description": "English: Click: disable/enable uBlock₀ for this site.\n\nCtrl+click: disable uBlock₀ only on this page." }, "popupPowerSwitchInfo1": { - "message": "Bu saytda uBlock₀-u dayandırmaq üçün düyməyə basın.\n\nYalnız bu səhifədə uBlock₀-u dayandırmaq üçün Ctrl və düyməyə basın.", + "message": "Bu sayt üçün uBlock₀-u sıradan çıxartmaq üçün klikləyin.\n\nYalnız bu səhifə üçün uBlock₀-u sıradan çıxartmaq üçün Ctrl+klikləyin.", "description": "Message to be read by screen readers" }, "popupPowerSwitchInfo2": { - "message": "Bu saytda uBlock₀-u işə salmaq üçün düyməyə basın.", + "message": "Bu saytda uBlock₀-u fəallaşdırmaq üçün klikləyin.", "description": "Message to be read by screen readers" }, "popupBlockedRequestPrompt": { @@ -92,7 +92,7 @@ "description": "English: since install" }, "popupOr": { - "message": "yaxud", + "message": "və ya", "description": "English: or" }, "popupBlockedOnThisPage_v2": { @@ -104,7 +104,7 @@ "description": "For the new mobile-friendly popup design" }, "popupDomainsConnected_v2": { - "message": "Qoşulmuş domenlər", + "message": "Bağlantı qurulmuş domenlər", "description": "For the new mobile-friendly popup design" }, "popupTipDashboard": { @@ -120,23 +120,23 @@ "description": "English: Enter element picker mode" }, "popupTipLog": { - "message": "Loggeri aç", + "message": "Jurnalı aç", "description": "Tooltip used for the logger icon in the panel" }, "popupTipNoPopups": { - "message": "Bu saytda peyda olan bütün pəncərələrin əngəllənməsini işə sal/dayandır", + "message": "Bu sayt üçün bütün açılan pəncələri aç/bağla", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoPopups1": { - "message": "Bu saytda peyda olan bütün pəncərələri əngəlləmək üçün düyməyə basın", + "message": "Bu saytda bütün açılan pəncərələri əngəlləmək üçün kliklə", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoPopups2": { - "message": "Bu saytda peyda olan bütün pəncərələri daha əngəlləməmək üçün düyməyə basın", + "message": "Bu saytdakı bütün açılan pəncələri artıq əngəlləməmək üçün kliklə", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoLargeMedia": { - "message": "Bu saytda böyük media elemetlərinin əngəllənməsini işə sal/dayandır", + "message": "Bu saytda böyük media elemetlərini əngəlləməyi aç/bağla", "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoLargeMedia1": { @@ -172,7 +172,7 @@ "description": "Tooltip for the no-remote-fonts per-site switch" }, "popupTipNoScripting1": { - "message": "Bu saytda JavaScript-i əngəlləmək üçün düyməyə basın", + "message": "Bu saytda JavaScript-i sıradan çıxartmaq üçün kliklə", "description": "Tooltip for the no-scripting per-site switch" }, "popupTipNoScripting2": { @@ -216,7 +216,7 @@ "description": "Tooltip when hovering the top-most cell of the local-rules column." }, "popupTipSaveRules": { - "message": "Dəyişiklikləri daimi etmək üçün düyməyə basın.", + "message": "Dəyişiklikləri daimi etmək üçün klikləyin.", "description": "Tooltip when hovering over the padlock in the dynamic filtering pane." }, "popupTipRevertRules": { @@ -671,6 +671,10 @@ "message": "icazə verilmiş", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "dəyişdirildi", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1-ci tərəf resurslar", "description": "A keyword in the built-in row filtering expression" @@ -908,7 +912,7 @@ "description": "No longer used" }, "subscribeButton": { - "message": "Subscribe", + "message": "Abunə ol", "description": "For the button used to subscribe to a filter list" }, "elapsedOneMinuteAgo": { @@ -1036,19 +1040,19 @@ "description": "Tooltip for the button used to lock scrolling between the views in the 'My rules' pane" }, "genericCopyToClipboard": { - "message": "Mübadilə buferinə kopyala", + "message": "Lövhəyə kopyala", "description": "Label for buttons used to copy something to the clipboard" }, "toggleBlockingProfile": { - "message": "Əngəlləmə profilini işə sal/söndür", + "message": "Əngəlləmə profilini aç/bağla", "description": "Label for keyboard shortcut used to toggle blocking profile" }, "relaxBlockingMode": { - "message": "Zəif əngəlləmə rejimi", + "message": "Əngəlləmə rejimini yüngülləşdir", "description": "Label for keyboard shortcut used to relax blocking mode (meant to replace 'Toggle blocking profile')" }, "storageUsed": { - "message": "İstifadə olunan yer: {{value}} {{unit}}", + "message": "İstifadə olunan anbar: {{value}} {{unit}}", "description": " In Setting pane, renders as (example): Storage used: 13.2 MB" }, "KB": { @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Yükləmək üçün kliklə", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/bg/messages.json b/src/_locales/bg/messages.json index 5c23ff52aad07..886854721de65 100644 --- a/src/_locales/bg/messages.json +++ b/src/_locales/bg/messages.json @@ -671,6 +671,10 @@ "message": "позволени", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "променен", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1-ви страни", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "ГБ", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Щракнете, за да се зареди", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Това поле трябва да бъде последното", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/bn/messages.json b/src/_locales/bn/messages.json index da56838043d5f..31bbf754729f1 100644 --- a/src/_locales/bn/messages.json +++ b/src/_locales/bn/messages.json @@ -671,6 +671,10 @@ "message": "অনুমোদিত", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "১ম-পক্ষ", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "গিগাবাইট", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/bs/messages.json b/src/_locales/bs/messages.json index 5b66addba637b..358a482fbae52 100644 --- a/src/_locales/bs/messages.json +++ b/src/_locales/bs/messages.json @@ -671,6 +671,10 @@ "message": "dozvoljeno", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1st-party", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/ca/messages.json b/src/_locales/ca/messages.json index 600ec6ef5ae46..c9d38b343aee9 100644 --- a/src/_locales/ca/messages.json +++ b/src/_locales/ca/messages.json @@ -671,6 +671,10 @@ "message": "permès", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modificat", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "primari", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Clic per carregar", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Aquesta entrada ha de ser l'última", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/cs/messages.json b/src/_locales/cs/messages.json index b592077527daf..a842a07c15984 100644 --- a/src/_locales/cs/messages.json +++ b/src/_locales/cs/messages.json @@ -671,6 +671,10 @@ "message": "povoleno", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "vlastní doména", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/cv/messages.json b/src/_locales/cv/messages.json index 4442361046cc7..a22e4c78ff6d2 100644 --- a/src/_locales/cv/messages.json +++ b/src/_locales/cv/messages.json @@ -671,6 +671,10 @@ "message": "allowed", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1st-party", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Ку ҫыру юлашки пулмалла", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/da/messages.json b/src/_locales/da/messages.json index 61d3b45659dab..f77dd3c3bc5f0 100644 --- a/src/_locales/da/messages.json +++ b/src/_locales/da/messages.json @@ -671,6 +671,10 @@ "message": "tilladte", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "ændret", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "førsteparts", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Klik for at indlæse", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Denne post skal være den sidste", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/de/messages.json b/src/_locales/de/messages.json index dfd9ea11e0d99..761cd8d36346d 100644 --- a/src/_locales/de/messages.json +++ b/src/_locales/de/messages.json @@ -12,7 +12,7 @@ "description": "English: uBlock₀ — Dashboard" }, "dashboardUnsavedWarning": { - "message": "Achtung! Du hast deine Änderungen nicht gespeichert", + "message": "Warnung! Nicht gespeicherte Änderungen", "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": "Positivliste", + "message": "Ausnahmeregeln", "description": "appears as tab name in dashboard" }, "shortcutsPageName": { @@ -64,7 +64,7 @@ "description": "Title for the advanced settings page" }, "popupPowerSwitchInfo": { - "message": "Klick: uBlock₀ für alle Seiten dieser Domain aktivieren/deaktivieren.\n\nStrg+Klick: uBlock₀ nur für die aktuelle Webseite deaktivieren.", + "message": "Klick: uBlock₀ für diese Website aktivieren/deaktivieren.\n\nStrg+Klick: uBlock₀ nur für die aktuelle Seite deaktivieren.", "description": "English: Click: disable/enable uBlock₀ for this site.\n\nCtrl+click: disable uBlock₀ only on this page." }, "popupPowerSwitchInfo1": { @@ -108,7 +108,7 @@ "description": "For the new mobile-friendly popup design" }, "popupTipDashboard": { - "message": "Klicken, um das Dashboard zu öffnen", + "message": "Klicken, um die Übersicht zu öffnen", "description": "English: Click to open the dashboard" }, "popupTipZapper": { @@ -116,7 +116,7 @@ "description": "Tooltip for the element-zapper icon in the popup panel" }, "popupTipPicker": { - "message": "Öffne den Element-Picker-Modus", + "message": "Element-Auswahlmodus starten", "description": "English: Enter element picker mode" }, "popupTipLog": { @@ -124,27 +124,27 @@ "description": "Tooltip used for the logger icon in the panel" }, "popupTipNoPopups": { - "message": "Blockieren von Popups für diese Seite an-/ausschalten", + "message": "Pop-ups auf dieser Seite blockieren/zulassen", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoPopups1": { - "message": "Hier klicken, um alle Popups auf dieser Seite zu blockieren", + "message": "Hier klicken, um alle Popups auf dieser Website zu blockieren", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoPopups2": { - "message": "Hier klicken, um Popups auf dieser Seite nicht mehr zu blockieren", + "message": "Hier klicken, um Popups auf dieser Website nicht mehr zu blockieren", "description": "Tooltip for the no-popups per-site switch" }, "popupTipNoLargeMedia": { - "message": "Das Blockieren großer Medienelemente auf dieser Seite an-/ausschalten", + "message": "Große Medienelemente dieser Seite anzeigen/sperren", "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoLargeMedia1": { - "message": "Hier klicken, um große Medienelemente auf dieser Seite zu blockieren", + "message": "Hier klicken, um große Medienelemente auf dieser Website zu blockieren", "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoLargeMedia2": { - "message": "Hier klicken, um große Medienelemente auf dieser Seite nicht mehr zu blockieren", + "message": "Hier klicken, um große Medienelemente auf dieser Website nicht mehr zu blockieren", "description": "Tooltip for the no-large-media per-site switch" }, "popupTipNoCosmeticFiltering": { @@ -152,11 +152,11 @@ "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoCosmeticFiltering1": { - "message": "Hier klicken, um Kosmetische Filter auf dieser Seite zu deaktivieren", + "message": "Hier klicken, um kosmetische Filter auf dieser Seite zu deaktivieren", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoCosmeticFiltering2": { - "message": "Hier klicken, um Kosmetische Filter auf dieser Seite zu aktivieren", + "message": "Hier klicken, um kosmetische Filter auf dieser Seite zu aktivieren", "description": "Tooltip for the no-cosmetic-filtering per-site switch" }, "popupTipNoRemoteFonts": { @@ -180,7 +180,7 @@ "description": "Tooltip for the no-scripting per-site switch" }, "popupNoPopups_v2": { - "message": "Pop-Up-Fenster", + "message": "Pop-up-Fenster", "description": "Caption for the no-popups per-site switch" }, "popupNoLargeMedia_v2": { @@ -300,7 +300,7 @@ "description": "An entry in the browser's contextual menu" }, "settingsCollapseBlockedPrompt": { - "message": "Verstecke die Platzhalter für blockierte Elemente", + "message": "Platzhalter für blockierte Elemente ausblenden", "description": "English: Hide placeholders of blocked elements" }, "settingsIconBadgePrompt": { @@ -396,7 +396,7 @@ "description": "A button in the in the _3rd-party filters_ pane" }, "3pPurgeAll": { - "message": "Leere alle Cache-Speicher", + "message": "Alle Cache-Speicher leeren", "description": "A button in the in the _3rd-party filters_ pane" }, "3pParseAllABPHideFiltersPrompt1": { @@ -404,7 +404,7 @@ "description": "English: Parse and enforce Adblock+ element hiding filters." }, "3pParseAllABPHideFiltersInfo": { - "message": "Diese Option ermöglicht die Analyse und Anwendung von Adblock-Plus-kompatiblen Filtern zum „Verstecken von Elementen“. Diese Filter sind grundsätzlich kosmetischer Natur und dienen zum Ausblenden von Elementen auf einer Webseite, die als optische Belästigung wahrgenommen werden und nicht von den vorhandenen Filtern geblockt werden können.\n\nDas Aktivieren dieser Option erhöht den Speicherbedarf von uBlock Origin.", + "message": "Kosmetische Filter dienen dazu, Elemente auf einer Webseite auszublenden, die als visuell störend empfunden werden und nicht von den auf Netzwerkanforderungen basierenden Filter-Engines blockiert werden können.", "description": "Describes the purpose of the 'Parse and enforce cosmetic filters' feature." }, "3pIgnoreGenericCosmeticFilters": { @@ -412,7 +412,7 @@ "description": "This will cause uBO to ignore all generic cosmetic filters." }, "3pIgnoreGenericCosmeticFiltersInfo": { - "message": "

Generische kosmetische Filter sind diejenigen kosmetischen Filter, die für die Anwendung auf allen Webseiten bestimmt sind.

Obwohl sie von uBlock₀ effizient verarbeitet werden, können sie dennoch auf einigen Webseiten - insbesondere auf den großen und langlebigen - eine messbare Belastung für Arbeitsspeicher und Prozessor bewirken.

Die Aktivierung dieser Option wird diese Mehrbelastung für Speicher und Prozessor auf bestimmten Webseiten durch die Verarbeitung generischer kosmetischer Filter verhindern und auch den von uBlock₀ in Anspruch genommenen Arbeitsspeicher verringern.

Es wird empfohlen, diese Option auf weniger leistungsstarken Geräten zu aktivieren.", + "message": "Generische kosmetische Filter sind diejenigen kosmetischen Filter, die für die Anwendung auf allen Webseiten bestimmt sind. Die Aktivierung dieser Option wird die Mehrbelastung für Speicher und Prozessor auf Webseiten durch die Verarbeitung generischer kosmetischer Filter verhindern.\n\nEs wird empfohlen, diese Option auf weniger leistungsstarken Geräten zu aktivieren.", "description": "Describes the purpose of the 'Ignore generic cosmetic filters' feature." }, "3pListsOfBlockedHostsHeader": { @@ -496,7 +496,7 @@ "description": "English: Export" }, "1pExportFilename": { - "message": "my-ublock-custom-filters_{{datetime}}.txt", + "message": "ublock-statische-filter_{{datetime}}.txt", "description": "English: my-ublock-static-filters_{{datetime}}.txt" }, "1pApplyChanges": { @@ -568,7 +568,7 @@ "description": "English: a sort option for list of rules." }, "whitelistPrompt": { - "message": "Ausnahmeregeln bestimmen, auf welchen Webseiten uBlock₀ nicht aktiv sein soll. Ein Eintrag pro Zeile. Ungültige Regeln werden stillschweigend ignoriert und auskommentiert.", + "message": "Ausnahmeregeln bestimmen, auf welchen Webseiten uBlock Origin nicht aktiv sein soll. Ein Eintrag pro Zeile. Ungültige Regeln werden ignoriert und auskommentiert.", "description": "The name of the trusted sites pane." }, "whitelistImport": { @@ -624,7 +624,7 @@ "description": "Tooltip for the DOM inspector button in the logger page" }, "loggerPopupPanelTip": { - "message": "Popup-Tafel umschalten", + "message": "Popup-Bereich umschalten", "description": "Tooltip for the popup panel button in the logger page" }, "loggerInfoTip": { @@ -640,7 +640,7 @@ "description": "Tooltip for the pause button in the logger page" }, "loggerUnpauseTip": { - "message": "Angehaltene Protokollierung fortsetzen", + "message": "Protokollierung fortsetzen", "description": "Tooltip for the play button in the logger page" }, "loggerRowFiltererButtonTip": { @@ -668,7 +668,11 @@ "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltinAllowed": { - "message": "Erlaubt", + "message": "erlaubt", + "description": "A keyword in the built-in row filtering expression" + }, + "loggerRowFiltererBuiltinModified": { + "message": "geändert", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltin1p": { @@ -700,7 +704,7 @@ "description": "Label to identify a context field (typically a hostname)" }, "loggerEntryDetailsRootContext": { - "message": "Wurzelkontext", + "message": "Grundkontext", "description": "Label to identify a root context field (typically a hostname)" }, "loggerEntryDetailsPartyness": { @@ -736,11 +740,11 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartBlock": { - "message": "Blockiere", + "message": "Blockieren", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartAllow": { - "message": "Erlaube", + "message": "Erlauben", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartType": { @@ -824,11 +828,11 @@ "description": "Label for radio-button to pick export format" }, "loggerExportEncodePlain": { - "message": "Text (unformatiert)", + "message": "Rohtext", "description": "Label for radio-button to pick export text format" }, "loggerExportEncodeMarkdown": { - "message": "Text (Markdown)", + "message": "Markdown", "description": "Label for radio-button to pick export text format" }, "aboutChangelog": { @@ -876,7 +880,7 @@ "description": "Text for button to create a backup of all settings" }, "aboutBackupFilename": { - "message": "my-ublock-backup_{{datetime}}.txt", + "message": "ublock-sicherung_{{datetime}}.txt", "description": "English: my-ublock-backup_{{datetime}}.txt" }, "aboutRestoreDataButton": { @@ -888,7 +892,7 @@ "description": "English: Reset to default settings..." }, "aboutRestoreDataConfirm": { - "message": "Alle Einstellungen werden überschrieben und auf den Stand von {{time}} gebracht. Anschließend wird uBlock neu gestartet.\n\nSollen die aktuellen Einstellungen durch das Backup ersetzt werden?", + "message": "Alle Einstellungen werden überschrieben und auf den Stand von {{time}} gebracht. Anschließend wird uBlock neu gestartet.\n\nSollen die aktuellen Einstellungen durch die Sicherung ersetzt werden?", "description": "Message asking user to confirm restore" }, "aboutRestoreDataError": { @@ -968,7 +972,7 @@ "description": "English: Go back" }, "docblockedClose": { - "message": "Schließe dieses Fenster", + "message": "Dieses Fenster schließen", "description": "English: Close this window" }, "docblockedProceed": { @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Zum Laden anklicken", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Dieser Eintrag muss der letzte sein", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/el/messages.json b/src/_locales/el/messages.json index b6513ada30b7b..e9579cc64e7f6 100644 --- a/src/_locales/el/messages.json +++ b/src/_locales/el/messages.json @@ -104,7 +104,7 @@ "description": "For the new mobile-friendly popup design" }, "popupDomainsConnected_v2": { - "message": "Domains connected", + "message": "Συνδεδεμένοι τομείς", "description": "For the new mobile-friendly popup design" }, "popupTipDashboard": { @@ -176,7 +176,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": { @@ -184,15 +184,15 @@ "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": "Remote fonts", + "message": "Απομακρυσμένες γραμματοσειρές", "description": "Caption for the no-remote-fonts per-site switch" }, "popupNoScripting_v2": { @@ -296,7 +296,7 @@ "description": "English: Click, Ctrl-click" }, "pickerContextMenuEntry": { - "message": "Αποκλεισμός στοιχείου", + "message": "Φραγή στοιχείου...", "description": "An entry in the browser's contextual menu" }, "settingsCollapseBlockedPrompt": { @@ -308,7 +308,7 @@ "description": "English: Show the number of blocked requests on the icon" }, "settingsTooltipsPrompt": { - "message": "Απενεργοποιήστε τις αιωρούμενες επεξηγήσεις", + "message": "Απενεργοποίηση υποδείξεων", "description": "A checkbox in the Settings pane" }, "settingsContextMenuPrompt": { @@ -552,19 +552,19 @@ "description": "English: dynamic rule syntax and full documentation." }, "rulesSort": { - "message": "Sort:", + "message": "Ταξινόμηση:", "description": "English: label for sort option." }, "rulesSortByType": { - "message": "Rule type", + "message": "Τύπος κανόνα", "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": { @@ -671,6 +671,10 @@ "message": "επιτρέπεται", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1st-party", "description": "A keyword in the built-in row filtering expression" @@ -716,7 +720,7 @@ "description": "Label to identify the URL of an entry" }, "loggerURLFilteringHeader": { - "message": "Φιλτράρισμα δυναμικών συνδέσμων", + "message": "Κανόνας URL", "description": "Small header to identify the dynamic URL filtering section" }, "loggerURLFilteringContextLabel": { @@ -804,7 +808,7 @@ "description": "A label for the time column" }, "loggerSettingHideColumnFilter": { - "message": "{{input}} Φίτρο/Κανόνας", + "message": "{{input}} Φίλτρο/κανόνας", "description": "A label for the filter or rule column" }, "loggerSettingHideColumnContext": { @@ -868,7 +872,7 @@ "description": "Link text to uBO's own filter lists repo" }, "aboutDependencies": { - "message": "External dependencies (GPLv3-compatible):", + "message": "Εξωτερικές εξαρτήσεις (συμβατές με GPLv3):", "description": "Shown in the About pane" }, "aboutBackupDataButton": { @@ -900,7 +904,7 @@ "description": "Message asking user to confirm reset" }, "errorCantConnectTo": { - "message": "Αδυναμία σύνδεσης με {{url}}", + "message": "Σφάλμα δικτύου: {{msg}}", "description": "English: Network error: {{msg}}" }, "subscriberConfirm": { @@ -908,7 +912,7 @@ "description": "No longer used" }, "subscribeButton": { - "message": "Subscribe", + "message": "Εγγραφή", "description": "For the button used to subscribe to a filter list" }, "elapsedOneMinuteAgo": { @@ -972,7 +976,7 @@ "description": "English: Close this window" }, "docblockedProceed": { - "message": "Απενεργοποιήστε αυστηρό μπλοκάρισμα για {{hostname}}", + "message": "Απενεργοποίηση αυστηρής φραγής για το {{hostname}}", "description": "English: Disable strict blocking for {{hostname}} ..." }, "docblockedDisableTemporary": { @@ -1048,7 +1052,7 @@ "description": "Label for keyboard shortcut used to relax blocking mode (meant to replace 'Toggle blocking profile')" }, "storageUsed": { - "message": "Storage used: {{value}} {{unit}}", + "message": "Χώρος σε χρήση: {{value}} {{unit}}", "description": " In Setting pane, renders as (example): Storage used: 13.2 MB" }, "KB": { @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Κάντε κλικ για φόρτωση", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Αυτή η καταχώρηση θα πρέπει να είναι τελευταία", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 79dea09037e3b..84dee24e960b5 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -671,6 +671,10 @@ "message": "allowed", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1st-party", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/en_GB/messages.json b/src/_locales/en_GB/messages.json index 3c4f5e0e21a25..293cc0662b52d 100644 --- a/src/_locales/en_GB/messages.json +++ b/src/_locales/en_GB/messages.json @@ -671,6 +671,10 @@ "message": "allowed", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1st-party", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/eo/messages.json b/src/_locales/eo/messages.json index 989b20aa9ad76..df8d433a9976d 100644 --- a/src/_locales/eo/messages.json +++ b/src/_locales/eo/messages.json @@ -671,6 +671,10 @@ "message": "permesata", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "rekta", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Alklaku por ŝarĝi", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/es/messages.json b/src/_locales/es/messages.json index 49f4cdf9230de..e93054f3af3bc 100644 --- a/src/_locales/es/messages.json +++ b/src/_locales/es/messages.json @@ -671,6 +671,10 @@ "message": "permitido", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modificado", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "petición del dominio", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Clic para cargar", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Esta entrada debe ser la última", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/et/messages.json b/src/_locales/et/messages.json index 863272cbc2bb7..abd7273f5abca 100644 --- a/src/_locales/et/messages.json +++ b/src/_locales/et/messages.json @@ -671,6 +671,10 @@ "message": "lubatud", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "muudetud", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1. osapool", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Klõpsa laadimiseks", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "See sisestus peab olema viimane", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/eu/messages.json b/src/_locales/eu/messages.json index 2423dae3120cf..eb0de1c763352 100644 --- a/src/_locales/eu/messages.json +++ b/src/_locales/eu/messages.json @@ -671,6 +671,10 @@ "message": "baimenduta", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "Lehen eskukoa", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/fa/messages.json b/src/_locales/fa/messages.json index f6d5c26c9e7b4..404bdc7f619c5 100644 --- a/src/_locales/fa/messages.json +++ b/src/_locales/fa/messages.json @@ -671,6 +671,10 @@ "message": "مجاز", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1st-party", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "این باید آخرین مطلب باشد", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/fi/messages.json b/src/_locales/fi/messages.json index 2eca76c6a9c47..a633c379fb159 100644 --- a/src/_locales/fi/messages.json +++ b/src/_locales/fi/messages.json @@ -671,6 +671,10 @@ "message": "sallittu", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1. osapuoli", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "Gt", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/fil/messages.json b/src/_locales/fil/messages.json index 97394462347fb..e9ca2931acd1f 100644 --- a/src/_locales/fil/messages.json +++ b/src/_locales/fil/messages.json @@ -96,11 +96,11 @@ "description": "English: or" }, "popupBlockedOnThisPage_v2": { - "message": "Blocked on this page", + "message": "Nabawal sa ditong pahina", "description": "For the new mobile-friendly popup design" }, "popupBlockedSinceInstall_v2": { - "message": "Blocked since install", + "message": "Nabawal mula noong pag-install", "description": "For the new mobile-friendly popup design" }, "popupDomainsConnected_v2": { @@ -184,15 +184,15 @@ "description": "Caption for the no-popups per-site switch" }, "popupNoLargeMedia_v2": { - "message": "Large media elements", + "message": "Malaking media na elements", "description": "Caption for the no-large-media per-site switch" }, "popupNoCosmeticFiltering_v2": { - "message": "Cosmetic filtering", + "message": "Pagsala ng kosmetiko", "description": "Caption for the no-cosmetic-filtering per-site switch" }, "popupNoRemoteFonts_v2": { - "message": "Remote fonts", + "message": "fonts ng remote", "description": "Caption for the no-remote-fonts per-site switch" }, "popupNoScripting_v2": { @@ -220,7 +220,7 @@ "description": "Tooltip when hovering over the padlock in the dynamic filtering pane." }, "popupTipRevertRules": { - "message": "Click to revert your changes.", + "message": "Pindutan upang ibalik ang iyong pag-bago.", "description": "Tooltip when hovering over the eraser in the dynamic filtering pane." }, "popupAnyRulePrompt": { @@ -244,15 +244,15 @@ "description": "" }, "popup1pScriptRulePrompt": { - "message": "1st-party scripts", + "message": "1st-party na mga script", "description": "" }, "popup3pScriptRulePrompt": { - "message": "3rd-party scripts", + "message": "3rd-party na mga script", "description": "" }, "popup3pFrameRulePrompt": { - "message": "3rd-party frames", + "message": "3rd-party na mga frame", "description": "" }, "popupHitDomainCountPrompt": { @@ -292,7 +292,7 @@ "description": "English: Cosmetic filters" }, "pickerCosmeticFiltersHint": { - "message": "Click, Ctrl-click", + "message": "Pindutin, Ctrl-pindot", "description": "English: Click, Ctrl-click" }, "pickerContextMenuEntry": { @@ -308,7 +308,7 @@ "description": "English: Show the number of blocked requests on the icon" }, "settingsTooltipsPrompt": { - "message": "Disable tooltips", + "message": "Wag i-pagana ang tooltips", "description": "A checkbox in the Settings pane" }, "settingsContextMenuPrompt": { @@ -344,7 +344,7 @@ "description": "English: " }, "settingPerSiteSwitchGroup": { - "message": "Default behavior", + "message": "Orihinal na pag-uugali", "description": "" }, "settingPerSiteSwitchGroupSynopsis": { @@ -352,23 +352,23 @@ "description": "" }, "settingsNoCosmeticFilteringPrompt": { - "message": "Disable cosmetic filtering", + "message": "Di-pinagana ang cosmetic filtering", "description": "" }, "settingsNoLargeMediaPrompt": { - "message": "Block media elements larger than {{input}} KB", + "message": "Bawalan ang mga media element na mas malaki sa {{input}} KB", "description": "" }, "settingsNoRemoteFontsPrompt": { - "message": "Block remote fonts", + "message": "Bawalan ang remote fonts", "description": "" }, "settingsNoScriptingPrompt": { - "message": "Disable JavaScript", + "message": "Di-pinagana ang JavaScript", "description": "The default state for the per-site no-scripting switch" }, "settingsNoCSPReportsPrompt": { - "message": "Block CSP reports", + "message": "Pagbawalin ang balita ng CSP", "description": "background information: https://github.com/gorhill/uBlock/issues/3150" }, "settingsLastRestorePrompt": { @@ -388,7 +388,7 @@ "description": "Appears aside each filter list in the _3rd-party filters_ pane" }, "3pAutoUpdatePrompt1": { - "message": "Auto-update filter lists", + "message": "I-awtomatik-update ang listahan ng filter", "description": "A checkbox in the _3rd-party filters_ pane" }, "3pUpdateNow": { @@ -396,7 +396,7 @@ "description": "A button in the in the _3rd-party filters_ pane" }, "3pPurgeAll": { - "message": "Purge all caches", + "message": "Purgahin ang lahat ng caches", "description": "A button in the in the _3rd-party filters_ pane" }, "3pParseAllABPHideFiltersPrompt1": { @@ -408,7 +408,7 @@ "description": "Describes the purpose of the 'Parse and enforce cosmetic filters' feature." }, "3pIgnoreGenericCosmeticFilters": { - "message": "Ignore generic cosmetic filters", + "message": "Huwag pansinin ang generic cosmetic filters", "description": "This will cause uBO to ignore all generic cosmetic filters." }, "3pIgnoreGenericCosmeticFiltersInfo": { @@ -424,7 +424,7 @@ "description": "English: Apply changes" }, "3pGroupDefault": { - "message": "Built-in", + "message": "nagawa-sa", "description": "Header for the uBlock filters section in 'Filter lists pane'" }, "3pGroupAds": { @@ -452,11 +452,11 @@ "description": "English: Regions, languages" }, "3pGroupCustom": { - "message": "Custom", + "message": "Pasadya", "description": "English: Custom" }, "3pImport": { - "message": "Import...", + "message": "Mag-import...", "description": "The label for the checkbox used to import external filter lists" }, "3pExternalListsHint": { @@ -468,7 +468,7 @@ "description": "used as a tooltip for the out-of-date icon beside a list" }, "3pViewContent": { - "message": "view content", + "message": "Tignan ang kaloob", "description": "used as a tooltip for eye icon beside a list" }, "3pLastUpdate": { @@ -476,7 +476,7 @@ "description": "used as a tooltip for the clock icon beside a list" }, "3pUpdating": { - "message": "Updating...", + "message": "Ina-update...", "description": "used as a tooltip for the spinner icon beside a list" }, "3pNetworkError": { @@ -504,7 +504,7 @@ "description": "English: Apply changes" }, "rulesPermanentHeader": { - "message": "Permanent rules", + "message": "Permanenteng batas", "description": "header" }, "rulesTemporaryHeader": { @@ -532,11 +532,11 @@ "description": "Will discard manually-edited content and exit manual-edit mode" }, "rulesImport": { - "message": "Import from file...", + "message": "Mag-import mula sa file...", "description": "" }, "rulesExport": { - "message": "Export to file", + "message": "I-export sa file", "description": "" }, "rulesDefaultFileName": { @@ -552,11 +552,11 @@ "description": "English: dynamic rule syntax and full documentation." }, "rulesSort": { - "message": "Sort:", + "message": "Ayusin", "description": "English: label for sort option." }, "rulesSortByType": { - "message": "Rule type", + "message": "Batas na uri", "description": "English: a sort option for list of rules." }, "rulesSortBySource": { @@ -564,7 +564,7 @@ "description": "English: a sort option for list of rules." }, "rulesSortByDestination": { - "message": "Destination", + "message": "Destinasyon", "description": "English: a sort option for list of rules." }, "whitelistPrompt": { @@ -576,7 +576,7 @@ "description": "English: Import and append" }, "whitelistExport": { - "message": "Export", + "message": "I-Export", "description": "English: Export" }, "whitelistExportFilename": { @@ -588,7 +588,7 @@ "description": "English: Apply changes" }, "logRequestsHeaderType": { - "message": "Type", + "message": "Uri", "description": "English: Type" }, "logRequestsHeaderDomain": { @@ -600,7 +600,7 @@ "description": "English: URL" }, "logRequestsHeaderFilter": { - "message": "Filter", + "message": "Salain", "description": "English: Filter" }, "logAll": { @@ -608,15 +608,15 @@ "description": "Appears in the logger's tab selector" }, "logBehindTheScene": { - "message": "Tabless", + "message": "Walang tab", "description": "Pretty name for behind-the-scene network requests" }, "loggerCurrentTab": { - "message": "Current tab", + "message": "Pangkasalukuyang tab", "description": "Appears in the logger's tab selector" }, "loggerReloadTip": { - "message": "Reload the tab content", + "message": "I-reload ang kaloob ng tab", "description": "Tooltip for the reload button in the logger page" }, "loggerDomInspectorTip": { @@ -668,31 +668,35 @@ "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltinAllowed": { - "message": "allowed", + "message": "Pinayagan", + "description": "A keyword in the built-in row filtering expression" + }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltin1p": { - "message": "1st-party", + "message": "1st-partido", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltin3p": { - "message": "3rd-party", + "message": "ikatlong-partido", "description": "A keyword in the built-in row filtering expression" }, "loggerEntryDetailsHeader": { - "message": "Details", + "message": "Detalye", "description": "Small header to identify the 'Details' pane for a specific logger entry" }, "loggerEntryDetailsFilter": { - "message": "Filter", + "message": "Salain", "description": "Label to identify a filter field" }, "loggerEntryDetailsFilterList": { - "message": "Filter list", + "message": "Salain ang listahan", "description": "Label to identify a filter list field" }, "loggerEntryDetailsRule": { - "message": "Rule", + "message": "Batas", "description": "Label to identify a rule field" }, "loggerEntryDetailsContext": { @@ -700,7 +704,7 @@ "description": "Label to identify a context field (typically a hostname)" }, "loggerEntryDetailsRootContext": { - "message": "Root context", + "message": "Ugat ng konteksto", "description": "Label to identify a root context field (typically a hostname)" }, "loggerEntryDetailsPartyness": { @@ -708,7 +712,7 @@ "description": "Label to identify a field providing partyness information" }, "loggerEntryDetailsType": { - "message": "Type", + "message": "Uri", "description": "Label to identify the type of an entry" }, "loggerEntryDetailsURL": { @@ -720,15 +724,15 @@ "description": "Small header to identify the dynamic URL filtering section" }, "loggerURLFilteringContextLabel": { - "message": "Context:", + "message": "Konteksto:", "description": "Label for the context selector" }, "loggerURLFilteringTypeLabel": { - "message": "Type:", + "message": "Uri:", "description": "Label for the type selector" }, "loggerStaticFilteringHeader": { - "message": "Static filter", + "message": "Static na pag-salain", "description": "Small header to identify the static filtering section" }, "loggerStaticFilteringSentence": { @@ -744,15 +748,15 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartType": { - "message": "type “{{type}}”", + "message": "uri \"{{type}}\"", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartAnyType": { - "message": "any type", + "message": "kahit anong uri", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartOrigin": { - "message": "from “{{origin}}”", + "message": "mula sa \"{{origin}}\"", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartAnyOrigin": { @@ -764,7 +768,7 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartImportant": { - "message": "even if", + "message": "kahit", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringFinderSentence1": { @@ -800,11 +804,11 @@ "description": "Logger settings: a sentence to describe the purpose of the checkboxes below" }, "loggerSettingHideColumnTime": { - "message": "{{input}} Time", + "message": "{{input}} Oras", "description": "A label for the time column" }, "loggerSettingHideColumnFilter": { - "message": "{{input}} Filter/rule", + "message": "{{input}} Salain/batas", "description": "A label for the filter or rule column" }, "loggerSettingHideColumnContext": { @@ -816,7 +820,7 @@ "description": "A label for the partyness column" }, "loggerExportFormatList": { - "message": "List", + "message": "Listahan", "description": "Label for radio-button to pick export format" }, "loggerExportFormatTable": { @@ -908,7 +912,7 @@ "description": "No longer used" }, "subscribeButton": { - "message": "Subscribe", + "message": "Mag-subscribe", "description": "For the button used to subscribe to a filter list" }, "elapsedOneMinuteAgo": { @@ -916,7 +920,7 @@ "description": "English: a minute ago" }, "elapsedManyMinutesAgo": { - "message": "{{value}} minutes ago", + "message": "{{value}} mga minuto ang nakalipas", "description": "English: {{value}} minutes ago" }, "elapsedOneHourAgo": { @@ -940,11 +944,11 @@ "description": "Firefox/Fennec-specific: Show Dashboard" }, "showNetworkLogButton": { - "message": "Show Logger", + "message": "Ipakita ang Logger", "description": "Firefox/Fennec-specific: Show Logger" }, "fennecMenuItemBlockingOff": { - "message": "off", + "message": "OFF", "description": "Firefox-specific: appears as 'uBlock₀ (off)'" }, "docblockedPrompt1": { @@ -960,7 +964,7 @@ "description": "label to be used for the parameter-less URL: https://cloud.githubusercontent.com/assets/585534/9832014/bfb1b8f0-593b-11e5-8a27-fba472a5529a.png" }, "docblockedFoundIn": { - "message": "Found in:", + "message": "Nahanap sa:", "description": "English: List of filter list names follows" }, "docblockedBack": { @@ -968,7 +972,7 @@ "description": "English: Go back" }, "docblockedClose": { - "message": "Close this window", + "message": "Sarado ang itong window", "description": "English: Close this window" }, "docblockedProceed": { @@ -1000,11 +1004,11 @@ "description": "" }, "cloudDeviceNamePrompt": { - "message": "This device name:", + "message": "Itong pangalan ng device:", "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": "Babala! Baguhin mo ang mga masulong setting sa iyong sariling peligro.", "description": "A warning to users at the top of 'Advanced settings' page" }, "genericSubmit": { @@ -1028,7 +1032,7 @@ "description": "A context menu entry, present when large media elements have been blocked on the current site" }, "shortcutCapturePlaceholder": { - "message": "Type a shortcut", + "message": "Mag-sulat ng shortcut", "description": "Placeholder string for input field used to capture a keyboard shortcut" }, "genericMergeViewScrollLock": { @@ -1036,7 +1040,7 @@ "description": "Tooltip for the button used to lock scrolling between the views in the 'My rules' pane" }, "genericCopyToClipboard": { - "message": "Copy to clipboard", + "message": "Kopyahin sa clipboard", "description": "Label for buttons used to copy something to the clipboard" }, "toggleBlockingProfile": { @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Pindutin upang mag-load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/fr/messages.json b/src/_locales/fr/messages.json index 82352c4d641cf..c7d852b7c99c7 100644 --- a/src/_locales/fr/messages.json +++ b/src/_locales/fr/messages.json @@ -671,6 +671,10 @@ "message": "autorisée", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "Modifié", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "Domaine de la page", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "Go", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Cliquez pour charger", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/fy/messages.json b/src/_locales/fy/messages.json index 37a04e2c36096..0ace855c266a4 100644 --- a/src/_locales/fy/messages.json +++ b/src/_locales/fy/messages.json @@ -671,6 +671,10 @@ "message": "tastien", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "aktuele domein", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Klik om te laden", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/gl/messages.json b/src/_locales/gl/messages.json index f36de8d58edbf..ba3adebebcb20 100644 --- a/src/_locales/gl/messages.json +++ b/src/_locales/gl/messages.json @@ -671,6 +671,10 @@ "message": "allowed", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1st-party", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Esta ten que ser a derradeira entrada", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/he/messages.json b/src/_locales/he/messages.json index 66548b3eb3e93..0d16cbff3db71 100644 --- a/src/_locales/he/messages.json +++ b/src/_locales/he/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": { @@ -40,7 +40,7 @@ "description": "appears as tab name in dashboard" }, "whitelistPageName": { - "message": "רשימה לבנה", + "message": "אתרים מהימנים", "description": "appears as tab name in dashboard" }, "shortcutsPageName": { @@ -108,7 +108,7 @@ "description": "For the new mobile-friendly popup design" }, "popupTipDashboard": { - "message": "פתח את פאנל הקונפיגורציות", + "message": "פתח את לוח המחוונים", "description": "English: Click to open the dashboard" }, "popupTipZapper": { @@ -484,7 +484,7 @@ "description": "used as a tooltip for error icon beside a list" }, "1pFormatHint": { - "message": "מסנן אחד לשורה. המסנן יכול להיות שם מארח פשוט, או מסנן תואם EasyList. שורות עם קידומת ! ייתקלו בהתעלמות.", + "message": "מסנן אחד לכל שורה. המסנן יכול להיות דומיין פשוט, או מסנן התואם ל- EasyList. שורות עם קידומת ! לא יפורשו.", "description": "Short information about how to create custom filters" }, "1pImport": { @@ -552,11 +552,11 @@ "description": "English: dynamic rule syntax and full documentation." }, "rulesSort": { - "message": "מיון:", + "message": "מיין לפי:", "description": "English: label for sort option." }, "rulesSortByType": { - "message": "סוג כלל", + "message": "סוג הרשומה", "description": "English: a sort option for list of rules." }, "rulesSortBySource": { @@ -568,7 +568,7 @@ "description": "English: a sort option for list of rules." }, "whitelistPrompt": { - "message": "הכוונות האתר המהימן מכתיבות באילו דפי רשת uBlock Origin צריך להיות מושבת. כניסה אחת לשורה. הכוונות בלתי תקפות ייתקלו בהתעלמות בשקט ויקבלו הערה.", + "message": "הרשומות באתרים המהימנים מציינות באילו דפי אינטרנט uBlock Origin לא יהיה פעיל. רשומה אחת בכל שורה. רשומות לא חוקיות תתעלמנה בשקט ויסומנו כהערות.", "description": "The name of the trusted sites pane." }, "whitelistImport": { @@ -580,7 +580,7 @@ "description": "English: Export" }, "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": { @@ -671,6 +671,10 @@ "message": "מאופשר", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "השתנה", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "צד-1", "description": "A keyword in the built-in row filtering expression" @@ -904,7 +908,7 @@ "description": "English: Network error: {{msg}}" }, "subscriberConfirm": { - "message": "uBlock₀: הוסף את הכתובת הבאה לרשימת הפילטרים המותאמים אישית שלך?\n\nכותרת: \"{{title}}\"\nכתובת URL: {{url}}", + "message": "הוסף את הכתובת הבאה לרשימת הפילטרים המותאמים אישית שלך?\n\nכותרת: \"{{title}}\"\nכתובת URL: {{url}}", "description": "No longer used" }, "subscribeButton": { @@ -936,7 +940,7 @@ "description": "English: {{value}} days ago" }, "showDashboardButton": { - "message": "הצג את פאנל הקונפיגורציות", + "message": "הצג את לוח המחוונים", "description": "Firefox/Fennec-specific: Show Dashboard" }, "showNetworkLogButton": { @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "לחץ על מנת לטעון", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "ערך זה חייב להיות האחרון", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/hi/messages.json b/src/_locales/hi/messages.json index d4a0fbd220f31..da3e1dc66e1b5 100644 --- a/src/_locales/hi/messages.json +++ b/src/_locales/hi/messages.json @@ -671,6 +671,10 @@ "message": "स्वीकार किया हुआ ", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "१ली-पार्टी ", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "जीबी", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/hr/messages.json b/src/_locales/hr/messages.json index 677247c7bf0c0..455818d374d51 100644 --- a/src/_locales/hr/messages.json +++ b/src/_locales/hr/messages.json @@ -671,6 +671,10 @@ "message": "dopušteno", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "promijenjeno", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "Prve strane", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Kliknite za pokretanje", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Ova stavka mora biti posljednja", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/hu/messages.json b/src/_locales/hu/messages.json index f2ea627b63d76..42ea760157ffd 100644 --- a/src/_locales/hu/messages.json +++ b/src/_locales/hu/messages.json @@ -671,6 +671,10 @@ "message": "engedélyezve", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1. fél", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Kattints a betöltéshez", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Ez a bejegyzés utolsó kell hogy legyen", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/hy/messages.json b/src/_locales/hy/messages.json index 3a1ed2dd6c010..350aec59aef38 100644 --- a/src/_locales/hy/messages.json +++ b/src/_locales/hy/messages.json @@ -671,6 +671,10 @@ "message": "թույլատրված", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1st-party", "description": "A keyword in the built-in row filtering expression" @@ -1012,7 +1016,7 @@ "description": "for generic 'Submit' buttons" }, "genericApplyChanges": { - "message": "Apply changes", + "message": "Կիրառել", "description": "for generic 'Apply changes' buttons" }, "genericRevert": { @@ -1063,6 +1067,10 @@ "message": "ԳԲ", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/id/messages.json b/src/_locales/id/messages.json index 530ea678b1a1f..d8675eedb3c64 100644 --- a/src/_locales/id/messages.json +++ b/src/_locales/id/messages.json @@ -671,6 +671,10 @@ "message": "diizinkan", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "diubah", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "pihak ke-1", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Klik untuk memuat", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Entri ini harus menjadi yang terakhir", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/it/messages.json b/src/_locales/it/messages.json index bb331cb56cae6..684adca4888bf 100644 --- a/src/_locales/it/messages.json +++ b/src/_locales/it/messages.json @@ -671,6 +671,10 @@ "message": "permesso", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modificato", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "Dominio corrente", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Clicca per caricare", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/ja/messages.json b/src/_locales/ja/messages.json index f10ef7998d7e2..c31e15c903017 100644 --- a/src/_locales/ja/messages.json +++ b/src/_locales/ja/messages.json @@ -40,7 +40,7 @@ "description": "appears as tab name in dashboard" }, "whitelistPageName": { - "message": "ホワイトリスト", + "message": "信頼されたサイト", "description": "appears as tab name in dashboard" }, "shortcutsPageName": { @@ -200,7 +200,7 @@ "description": "Caption for the no-scripting per-site switch" }, "popupMoreButton_v2": { - "message": "詳細を表示", + "message": "表示量を増やす", "description": "Label to be used to show popup panel sections" }, "popupLessButton_v2": { @@ -484,7 +484,7 @@ "description": "used as a tooltip for error icon beside a list" }, "1pFormatHint": { - "message": "1行につき1つのフィルターです。フィルターはただのホストネームでもAdblock Plus適合のフィルターでも構いません。‘!’ですでに固定されている行は無視されます。", + "message": "1行につき1つのフィルターです。フィルターはただのホストネームでもAdblock Plus書式のフィルターでも構いません。! が先頭にある行は無視されます。", "description": "Short information about how to create custom filters" }, "1pImport": { @@ -580,7 +580,7 @@ "description": "English: Export" }, "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": { @@ -664,11 +664,15 @@ "description": "A keyword in the built-in row filtering expression: all items corresponding to uBO doing something (blocked, allowed, redirected, etc.)" }, "loggerRowFiltererBuiltinBlocked": { - "message": "ブロック済み", + "message": "ブロックした", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltinAllowed": { - "message": "許可済み", + "message": "許可した", + "description": "A keyword in the built-in row filtering expression" + }, + "loggerRowFiltererBuiltinModified": { + "message": "変更した", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltin1p": { @@ -772,7 +776,7 @@ "description": "Below this sentence, the filter list(s) in which the filter was found" }, "loggerStaticFilteringFinderSentence2": { - "message": "現在 有効にしているフィルターの中には、静的フィルター {{filter}} はありません", + "message": "現在 有効にしているフィルターの中には、静的フィルターが見つかりませんでした", "description": "Message to show when a filter cannot be found in any filter lists" }, "loggerSettingDiscardPrompt": { @@ -904,7 +908,7 @@ "description": "English: Network error: {{msg}}" }, "subscriberConfirm": { - "message": "uBlock₀: 以下のURLをカスタムフィルターに追加しますか?\n\nタイトル: \"{{title}}\"\nURL: {{url}}", + "message": "以下のURLをカスタムフィルターに追加しますか?\n\nタイトル: \"{{title}}\"\nURL: {{url}}", "description": "No longer used" }, "subscribeButton": { @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "クリックで、ロードする", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "これは最後のエントリである必要があります", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/ka/messages.json b/src/_locales/ka/messages.json index c39d4f879d941..96bf7d83f7e41 100644 --- a/src/_locales/ka/messages.json +++ b/src/_locales/ka/messages.json @@ -671,6 +671,10 @@ "message": "დაშვებული", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "ჩასწორებული", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "მონახულებულის", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "გბ", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "დაწკაპეთ ჩასატვირთად", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/kk/messages.json b/src/_locales/kk/messages.json index 2b9a4f2af7201..dd6c0883284d2 100644 --- a/src/_locales/kk/messages.json +++ b/src/_locales/kk/messages.json @@ -671,6 +671,10 @@ "message": "рұқсаты", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1-ші тарап", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "ГБ", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/kn/messages.json b/src/_locales/kn/messages.json index 9f5f4c9ab0ed6..efe96934bfbad 100644 --- a/src/_locales/kn/messages.json +++ b/src/_locales/kn/messages.json @@ -671,6 +671,10 @@ "message": "allowed", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1st-party", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/ko/messages.json b/src/_locales/ko/messages.json index c7202fc91ff8d..a29173fe06b1e 100644 --- a/src/_locales/ko/messages.json +++ b/src/_locales/ko/messages.json @@ -671,6 +671,10 @@ "message": "허용됨", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "퍼스트 파티", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "불러오려면 클릭하기", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/lt/messages.json b/src/_locales/lt/messages.json index a5b2859d76b47..cca81cf2ef3db 100644 --- a/src/_locales/lt/messages.json +++ b/src/_locales/lt/messages.json @@ -671,6 +671,10 @@ "message": "leidžiama", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1-oji šalis", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/lv/messages.json b/src/_locales/lv/messages.json index e324b7d7e55c9..a541731ffa5e2 100644 --- a/src/_locales/lv/messages.json +++ b/src/_locales/lv/messages.json @@ -671,6 +671,10 @@ "message": "allowed", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1st-party", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Šim ierakstam ir jābūt pēdējam", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/ml/messages.json b/src/_locales/ml/messages.json index d91db7f08b785..a0b3253a91a5b 100644 --- a/src/_locales/ml/messages.json +++ b/src/_locales/ml/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": "Stay", + "message": "താമസിക്കുക", "description": "Label for button to prevent navigating away from unsaved changes" }, "dashboardUnsavedWarningIgnore": { @@ -24,7 +24,7 @@ "description": "Label for button to ignore unsaved changes" }, "settingsPageName": { - "message": "സെറ്റിംഗ്സ്", + "message": "ക്രമീകരണം", "description": "appears as tab name in dashboard" }, "3pPageName": { @@ -44,7 +44,7 @@ "description": "appears as tab name in dashboard" }, "shortcutsPageName": { - "message": "Shortcuts", + "message": "കുറുക്കുവഴികൾ", "description": "appears as tab name in dashboard" }, "statsPageName": { @@ -56,11 +56,11 @@ "description": "appears as tab name in dashboard" }, "assetViewerPageName": { - "message": "uBlock₀ — Asset viewer", + "message": "uBlock₀ - അസറ്റ് വ്യൂവർ", "description": "Title for the asset viewer page" }, "advancedSettingsPageName": { - "message": "Advanced settings", + "message": "വിപുലമായ ക്രമീകരണങ്ങൾ", "description": "Title for the advanced settings page" }, "popupPowerSwitchInfo": { @@ -68,11 +68,11 @@ "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": { - "message": "Click to enable uBlock₀ for this site.", + "message": "ഈ സൈറ്റിനായി uBlock₀ പ്രവർത്തനക്ഷമമാക്കാൻ ക്ലിക്കുചെയ്യുക.", "description": "Message to be read by screen readers" }, "popupBlockedRequestPrompt": { @@ -96,15 +96,15 @@ "description": "English: or" }, "popupBlockedOnThisPage_v2": { - "message": "Blocked on this page", + "message": "ഈ പേജിൽ തടഞ്ഞു", "description": "For the new mobile-friendly popup design" }, "popupBlockedSinceInstall_v2": { - "message": "Blocked since install", + "message": "ഇൻസ്റ്റാളുചെയ്‌തതിനുശേഷം തടഞ്ഞു", "description": "For the new mobile-friendly popup design" }, "popupDomainsConnected_v2": { - "message": "Domains connected", + "message": "ഡൊമെയ്‌നുകൾ കണക്റ്റുചെയ്‌തു", "description": "For the new mobile-friendly popup design" }, "popupTipDashboard": { @@ -112,7 +112,7 @@ "description": "English: Click to open the dashboard" }, "popupTipZapper": { - "message": "Enter element zapper mode", + "message": "ഘടക സപ്പർ മോഡ് നൽകുക", "description": "Tooltip for the element-zapper icon in the popup panel" }, "popupTipPicker": { @@ -128,23 +128,23 @@ "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": { @@ -152,11 +152,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": { @@ -164,47 +164,47 @@ "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": "ഈ സൈറ്റിൽ JavaScript അപ്രാപ്തമാക്കാൻ ക്ലിക്കുചെയ്യുക", "description": "Tooltip for the no-scripting per-site switch" }, "popupTipNoScripting2": { - "message": "Click to no longer disable JavaScript on this site", + "message": "ഈ സൈറ്റിൽ‌ ഇനിമുതൽ‌ JavaScript അപ്രാപ്‌തമാക്കുന്നതിന് ക്ലിക്കുചെയ്യുക", "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": "Remote fonts", + "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": { - "message": "More", + "message": "കൂടുതൽ", "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": { @@ -264,7 +264,7 @@ "description": "appears in popup" }, "popupVersion": { - "message": "Version", + "message": "പതിപ്പ്", "description": "Example of use: Version 1.26.4" }, "pickerCreate": { @@ -280,7 +280,7 @@ "description": "English: Quit" }, "pickerPreview": { - "message": "Preview", + "message": "പ്രിവ്യൂ", "description": "Element picker preview mode: will cause the elements matching the current filter to be removed from the page" }, "pickerNetFilters": { @@ -328,7 +328,7 @@ "description": "" }, "settingsAdvancedUserSettings": { - "message": "advanced settings", + "message": "വിപുലമായ ക്രമീകരണങ്ങൾ", "description": "For the tooltip of a link which gives access to advanced settings" }, "settingsPrefetchingDisabledPrompt": { @@ -348,7 +348,7 @@ "description": "" }, "settingPerSiteSwitchGroupSynopsis": { - "message": "These default behaviors can be overridden on a per-site basis", + "message": "ഓരോ സ്ഥിരസ്ഥിതി അടിസ്ഥാനത്തിലും ഈ സ്ഥിരസ്ഥിതി പെരുമാറ്റങ്ങൾ അസാധുവാക്കാനാകും", "description": "" }, "settingsNoCosmeticFilteringPrompt": { @@ -356,7 +356,7 @@ "description": "" }, "settingsNoLargeMediaPrompt": { - "message": "Block media elements larger than {{input}} KB", + "message": "മീഡിയ ഘടകങ്ങളെക്കാൾ വലുത് തടയുക {{input}} KB", "description": "" }, "settingsNoRemoteFontsPrompt": { @@ -364,11 +364,11 @@ "description": "" }, "settingsNoScriptingPrompt": { - "message": "Disable JavaScript", + "message": "ജാവാസ്ക്രിപ്റ്റ് അപ്രാപ്തമാക്കുക", "description": "The default state for the per-site no-scripting switch" }, "settingsNoCSPReportsPrompt": { - "message": "Block CSP reports", + "message": "സി‌എസ്‌പി റിപ്പോർട്ടുകൾ തടയുക", "description": "background information: https://github.com/gorhill/uBlock/issues/3150" }, "settingsLastRestorePrompt": { @@ -404,15 +404,15 @@ "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." }, "3pListsOfBlockedHostsHeader": { @@ -424,7 +424,7 @@ "description": "English: Apply changes" }, "3pGroupDefault": { - "message": "Built-in", + "message": "അന്തർനിർമ്മിതം", "description": "Header for the uBlock filters section in 'Filter lists pane'" }, "3pGroupAds": { @@ -440,7 +440,7 @@ "description": "English: Malware domains" }, "3pGroupAnnoyances": { - "message": "Annoyances", + "message": "ശല്യപ്പെടുത്തലുകൾ", "description": "The header identifying the filter lists in the category 'annoyances'" }, "3pGroupMultipurpose": { @@ -456,7 +456,7 @@ "description": "English: Custom" }, "3pImport": { - "message": "Import...", + "message": "ഇറക്കുമതി ചെയ്യുക ...", "description": "The label for the checkbox used to import external filter lists" }, "3pExternalListsHint": { @@ -468,7 +468,7 @@ "description": "used as a tooltip for the out-of-date icon beside a list" }, "3pViewContent": { - "message": "view content", + "message": "ഉള്ളടക്കം കാണുക", "description": "used as a tooltip for eye icon beside a list" }, "3pLastUpdate": { @@ -476,11 +476,11 @@ "description": "used as a tooltip for the clock icon beside a list" }, "3pUpdating": { - "message": "Updating...", + "message": "അപ്‌ഡേറ്റുചെയ്യുന്നു ...", "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" }, "1pFormatHint": { @@ -552,19 +552,19 @@ "description": "English: dynamic rule syntax and full documentation." }, "rulesSort": { - "message": "Sort:", + "message": "അടുക്കുക:", "description": "English: label for sort option." }, "rulesSortByType": { - "message": "Rule type", + "message": "റൂൾ തരം", "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": { @@ -612,39 +612,39 @@ "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": { @@ -652,11 +652,11 @@ "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": { @@ -664,55 +664,59 @@ "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": "തിരുത്തപ്പെട്ടത്", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltin1p": { - "message": "1st-party", + "message": "ഒന്നാം കക്ഷി", "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltin3p": { - "message": "3rd-party", + "message": "തേര്‍ഡ് പാര്‍ട്ടി", "description": "A keyword in the built-in row filtering expression" }, "loggerEntryDetailsHeader": { - "message": "Details", + "message": "വിശദാംശങ്ങൾ", "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": { - "message": "Filter list", + "message": "ലിസ്റ്റ് ഫിൽട്ടർ ചെയ്യുക", "description": "Label to identify a filter list field" }, "loggerEntryDetailsRule": { - "message": "Rule", + "message": "ഭരണം", "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": { - "message": "URL", + "message": "URL\n", "description": "Label to identify the URL of an entry" }, "loggerURLFilteringHeader": { @@ -732,7 +736,7 @@ "description": "Small header to identify the static filtering section" }, "loggerStaticFilteringSentence": { - "message": "{{action}} network requests of {{type}} {{br}}which URL address matches {{url}} {{br}}and which originates {{origin}},{{br}}{{importance}} there is a matching exception filter.", + "message": "URL {{action}} നെറ്റ്വർക്ക് അഭ്യർത്ഥനകൾ {{type}} {{br}} ഏത് URL വിലാസം പൊരുത്തപ്പെടുന്നു {{url}} {{br}}, ഒപ്പം {{origin}}, {{br}} {{importance}} an പൊരുത്തപ്പെടുന്ന ഒഴിവാക്കൽ ഫിൽട്ടർ ഉണ്ട്.", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartBlock": { @@ -772,63 +776,63 @@ "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": { - "message": "{{input}} Time", + "message": "{{input}} സമയം", "description": "A label for the time column" }, "loggerSettingHideColumnFilter": { - "message": "{{input}} Filter/rule", + "message": "{{input}} ഫിൽട്ടർ / റൂൾ", "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": { - "message": "Table", + "message": "മേശ", "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" }, "aboutChangelog": { @@ -840,11 +844,11 @@ "description": "English: project' wiki on GitHub" }, "aboutSupport": { - "message": "Support", + "message": "പിന്തുണ", "description": "A link for where to get support" }, "aboutIssues": { - "message": "Issue tracker", + "message": "ഇഷ്യു ട്രാക്കർ", "description": "Text for a link to official issue tracker" }, "aboutCode": { @@ -856,19 +860,19 @@ "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" }, "aboutBackupDataButton": { @@ -908,7 +912,7 @@ "description": "No longer used" }, "subscribeButton": { - "message": "Subscribe", + "message": "സബ്‌സ്‌ക്രൈബുചെയ്യുക", "description": "For the button used to subscribe to a filter list" }, "elapsedOneMinuteAgo": { @@ -1004,7 +1008,7 @@ "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": { @@ -1012,7 +1016,7 @@ "description": "for generic 'Submit' buttons" }, "genericApplyChanges": { - "message": "Apply changes", + "message": "മാറ്റങ്ങൾ വരുത്തു", "description": "for generic 'Apply changes' buttons" }, "genericRevert": { @@ -1028,41 +1032,45 @@ "description": "A context menu entry, present when large media elements have been blocked on the current site" }, "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" }, "toggleBlockingProfile": { - "message": "Toggle blocking profile", + "message": "തടയൽ പ്രൊഫൈൽ ടോഗിൾ ചെയ്യുക", "description": "Label for keyboard shortcut used to toggle blocking profile" }, "relaxBlockingMode": { - "message": "Relax blocking mode", + "message": "തടയൽ മോഡ് വിശ്രമിക്കുക", "description": "Label for keyboard shortcut used to relax blocking mode (meant to replace 'Toggle blocking profile')" }, "storageUsed": { - "message": "Storage used: {{value}} {{unit}}", + "message": "ഉപയോഗിച്ച സംഭരണം: {{value}} {{unit}}", "description": " In Setting pane, renders as (example): Storage used: 13.2 MB" }, "KB": { - "message": "KB", + "message": "കെ.ബി.", "description": "short for 'kilobytes'" }, "MB": { - "message": "MB", + "message": "എം.ബി.", "description": "short for 'megabytes'" }, "GB": { - "message": "GB", + "message": "ജി.ബി.", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "ലോഡുചെയ്യാൻ ക്ലിക്കുചെയ്യുക", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/mr/messages.json b/src/_locales/mr/messages.json index 0ecb204596d8b..81beab697e1ab 100644 --- a/src/_locales/mr/messages.json +++ b/src/_locales/mr/messages.json @@ -671,6 +671,10 @@ "message": "allowed", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1st-party", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/ms/messages.json b/src/_locales/ms/messages.json index 8c0e7e7f69f7f..99aefed5be701 100644 --- a/src/_locales/ms/messages.json +++ b/src/_locales/ms/messages.json @@ -484,7 +484,7 @@ "description": "used as a tooltip for error icon beside a list" }, "1pFormatHint": { - "message": "One filter per line. A filter can be a plain hostname, or an EasyList-compatible filter. Lines prefixed with ! will be ignored.", + "message": "Satu penapis setiap baris. Penapis boleh menjadi nama hos biasa, atau penapis yang sesuai dengan Daftar Mudah. Garis yang diawali dengan ! akan diabaikan.", "description": "Short information about how to create custom filters" }, "1pImport": { @@ -496,7 +496,7 @@ "description": "English: Export" }, "1pExportFilename": { - "message": "my-ublock-static-filters_{{datetime}}.txt", + "message": "my-ublock-static-filter _ {{datetime}}. txt", "description": "English: my-ublock-static-filters_{{datetime}}.txt" }, "1pApplyChanges": { @@ -540,35 +540,35 @@ "description": "" }, "rulesDefaultFileName": { - "message": "my-ublock-dynamic-rules_{{datetime}}.txt", + "message": "my-ublock-dynamic-rules_{{datetime}}.txt\n", "description": "default file name to use" }, "rulesHint": { - "message": "List of your dynamic filtering rules.", + "message": "Senaraikan peraturan penapisan dinamik anda.", "description": "English: List of your dynamic filtering rules." }, "rulesFormatHint": { - "message": "Rule syntax: source destination type action (full documentation).", + "message": "Sintaks peraturan: tindakan jenis tujuan sumber ( dokumentasi lengkap ).", "description": "English: dynamic rule syntax and full documentation." }, "rulesSort": { - "message": "Sort:", + "message": "Susun:", "description": "English: label for sort option." }, "rulesSortByType": { - "message": "Rule type", + "message": "Jenis peraturan", "description": "English: a sort option for list of rules." }, "rulesSortBySource": { - "message": "Source", + "message": "Sumber", "description": "English: a sort option for list of rules." }, "rulesSortByDestination": { - "message": "Destination", + "message": "Destinasi", "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. Invalid directives will be silently ignored and commented out.", + "message": "Arahan laman web yang dipercayai menentukan halaman web mana uBlock Origin harus dilumpuhkan. Satu penyertaan setiap baris. Arahan tidak sah akan diam-diam diabaikan dan dikomentari.", "description": "The name of the trusted sites pane." }, "whitelistImport": { @@ -580,7 +580,7 @@ "description": "English: Export" }, "whitelistExportFilename": { - "message": "my-ublock-trusted-sites_{{datetime}}.txt", + "message": "my-ublock-trusted-sites_{{datetime}}.txt\n", "description": "The default filename to use for import/export purpose" }, "whitelistApply": { @@ -671,6 +671,10 @@ "message": "dibenarkan", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "diubah suai", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "pihak pertama", "description": "A keyword in the built-in row filtering expression" @@ -732,7 +736,7 @@ "description": "Small header to identify the static filtering section" }, "loggerStaticFilteringSentence": { - "message": "{{action}} network requests of {{type}} {{br}}which URL address matches {{url}} {{br}}and which originates {{origin}},{{br}}{{importance}} there is a matching exception filter.", + "message": "{{action}} permintaan rangkaian {{type}} {{br}} alamat URL yang sesuai dengan {{url}} {{br}} dan mana yang berasal {{origin}}, {{br}} {{kepentingan} } ada penapis pengecualian yang sepadan.", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartBlock": { @@ -756,79 +760,79 @@ "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartAnyOrigin": { - "message": "from anywhere", + "message": "dari mana-mana ", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartNotImportant": { - "message": "except when", + "message": "kecuali bila", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringSentencePartImportant": { - "message": "even if", + "message": "walaupun", "description": "Used in the static filtering wizard" }, "loggerStaticFilteringFinderSentence1": { - "message": "Static filter {{filter}} found in:", + "message": "Penapis statik {{filter}} terdapat di:", "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": "Penapis statik tidak dapat dijumpai dalam daftar penapis yang diaktifkan sekarang", "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": "Entri logger yang tidak memenuhi ketiga-tiga syarat di bawah akan dibuang secara automatik:", "description": "Logger setting: A sentence to describe the purpose of the settings below" }, "loggerSettingPerEntryMaxAge": { - "message": "Preserve entries from the last {{input}} minutes", + "message": "Simpan entri dari {{input}} minit terakhir", "description": "A logger setting" }, "loggerSettingPerTabMaxLoads": { - "message": "Preserve at most {{input}} page loads per tab", + "message": "Simpan paling banyak {{input}} pemuatan halaman setiap tab", "description": "A logger setting" }, "loggerSettingPerTabMaxEntries": { - "message": "Preserve at most {{input}} entries per tab", + "message": "Simpan paling banyak {{input}} entri setiap tab", "description": "A logger setting" }, "loggerSettingPerEntryLineCount": { - "message": "Use {{input}} lines per entry in vertically expanded mode", + "message": "Gunakan baris {{input}} setiap entri dalam mod yang diluaskan secara menegak", "description": "A logger setting" }, "loggerSettingHideColumnsPrompt": { - "message": "Hide columns:", + "message": "Sembunyikan lajur:", "description": "Logger settings: a sentence to describe the purpose of the checkboxes below" }, "loggerSettingHideColumnTime": { - "message": "{{input}} Time", + "message": "{{input}} Masa", "description": "A label for the time column" }, "loggerSettingHideColumnFilter": { - "message": "{{input}} Filter/rule", + "message": "{{input}} Tapis / peraturan", "description": "A label for the filter or rule column" }, "loggerSettingHideColumnContext": { - "message": "{{input}} Context", + "message": "{{input}} Konteks", "description": "A label for the context column" }, "loggerSettingHideColumnPartyness": { - "message": "{{input}} Partyness", + "message": "{{input}} Kesopanan", "description": "A label for the partyness column" }, "loggerExportFormatList": { - "message": "List", + "message": "Senarai", "description": "Label for radio-button to pick export format" }, "loggerExportFormatTable": { - "message": "Table", + "message": "Jadual", "description": "Label for radio-button to pick export format" }, "loggerExportEncodePlain": { - "message": "Plain", + "message": "Kosong", "description": "Label for radio-button to pick export text format" }, "loggerExportEncodeMarkdown": { - "message": "Markdown", + "message": "Penurunan harga", "description": "Label for radio-button to pick export text format" }, "aboutChangelog": { @@ -840,11 +844,11 @@ "description": "English: project' wiki on GitHub" }, "aboutSupport": { - "message": "Support", + "message": "Sokongan", "description": "A link for where to get support" }, "aboutIssues": { - "message": "Issue tracker", + "message": "Pengesan masalah", "description": "Text for a link to official issue tracker" }, "aboutCode": { @@ -852,67 +856,67 @@ "description": "English: Source code (GPLv3)" }, "aboutContributors": { - "message": "Contributors", + "message": "Penyumbang", "description": "English: Contributors" }, "aboutSourceCode": { - "message": "Source code", + "message": "Kod sumber", "description": "Link text to source code repo" }, "aboutTranslations": { - "message": "Translations", + "message": "Terjemahan", "description": "Link text to translations repo" }, "aboutFilterLists": { - "message": "Filter lists", + "message": "Senarai penapis", "description": "Link text to uBO's own filter lists repo" }, "aboutDependencies": { - "message": "External dependencies (GPLv3-compatible):", + "message": "Pergantungan luaran (serasi dengan GPLv3):", "description": "Shown in the About pane" }, "aboutBackupDataButton": { - "message": "Back up to file", + "message": "Sandarkan ke fail", "description": "Text for button to create a backup of all settings" }, "aboutBackupFilename": { - "message": "my-ublock-backup_{{datetime}}.txt", + "message": "my-ublock-backup_{{datetime}}.txt\n", "description": "English: my-ublock-backup_{{datetime}}.txt" }, "aboutRestoreDataButton": { - "message": "Restore from file...", + "message": "Pulihkan dari fail ...", "description": "English: Restore from file..." }, "aboutResetDataButton": { - "message": "Reset to default settings...", + "message": "Tetapkan semula ke tetapan lalai ...", "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": "Semua tetapan anda akan ditimpa menggunakan data yang disandarkan pada {{time}}, dan uBlock₀ akan dimulakan semula.\n\nMenimpa semua tetapan yang ada menggunakan data yang disandarkan?", "description": "Message asking user to confirm restore" }, "aboutRestoreDataError": { - "message": "The data could not be read or is invalid", + "message": "Data tidak dapat dibaca atau tidak sah", "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": "Semua tetapan anda akan dikeluarkan, dan uBlock₀ akan dimulakan semula.\n\nTetapkan semula uBlock₀ ke tetapan kilang?", "description": "Message asking user to confirm reset" }, "errorCantConnectTo": { - "message": "Network error: {{msg}}", + "message": "Ralat rangkaian: {{msg}}", "description": "English: Network error: {{msg}}" }, "subscriberConfirm": { - "message": "Add the following URL to your custom filter lists?\n\nTitle: \"{{title}}\"\nURL: {{url}}", + "message": "Tambahkan URL berikut ke senarai penapis tersuai anda?\n\nTajuk: \"{{title}}\"\nURL: {{url}}", "description": "No longer used" }, "subscribeButton": { - "message": "Subscribe", + "message": "Langgan", "description": "For the button used to subscribe to a filter list" }, "elapsedOneMinuteAgo": { - "message": "a minute ago", + "message": "seminit yang lalu", "description": "English: a minute ago" }, "elapsedManyMinutesAgo": { @@ -920,7 +924,7 @@ "description": "English: {{value}} minutes ago" }, "elapsedOneHourAgo": { - "message": "an hour ago", + "message": "satu jam yang lalu", "description": "English: an hour ago" }, "elapsedManyHoursAgo": { @@ -928,7 +932,7 @@ "description": "English: {{value}} hours ago" }, "elapsedOneDayAgo": { - "message": "a day ago", + "message": "sehari yang lalu", "description": "English: a day ago" }, "elapsedManyDaysAgo": { @@ -936,31 +940,31 @@ "description": "English: {{value}} days ago" }, "showDashboardButton": { - "message": "Show Dashboard", + "message": "Tunjukkan Papan Pemuka", "description": "Firefox/Fennec-specific: Show Dashboard" }, "showNetworkLogButton": { - "message": "Show Logger", + "message": "Tunjukkan Logger", "description": "Firefox/Fennec-specific: Show Logger" }, "fennecMenuItemBlockingOff": { - "message": "off", + "message": "mati", "description": "Firefox-specific: appears as 'uBlock₀ (off)'" }, "docblockedPrompt1": { - "message": "uBlock Origin has prevented the following page from loading:", + "message": "uBlock Origin menghalang halaman berikut memuatkan:", "description": "Used in the strict-blocking page" }, "docblockedPrompt2": { - "message": "Because of the following filter:", + "message": "Kerana penapis berikut:", "description": "Used in the strict-blocking page" }, "docblockedNoParamsPrompt": { - "message": "without parameters", + "message": "tanpa parameter", "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": "Dijumpai di:", "description": "English: List of filter list names follows" }, "docblockedBack": { @@ -968,11 +972,11 @@ "description": "English: Go back" }, "docblockedClose": { - "message": "Close this window", + "message": "Tutup tetingkap ini", "description": "English: Close this window" }, "docblockedProceed": { - "message": "Disable strict blocking for {{hostname}}", + "message": "Lumpuhkan sekatan ketat untuk {{hostname}}", "description": "English: Disable strict blocking for {{hostname}} ..." }, "docblockedDisableTemporary": { @@ -984,15 +988,15 @@ "description": "English: Permanently" }, "cloudPush": { - "message": "Export to cloud storage", + "message": "Eksport ke storan awan", "description": "tooltip" }, "cloudPull": { - "message": "Import from cloud storage", + "message": "Import dari storan awan", "description": "tooltip" }, "cloudPullAndMerge": { - "message": "Import from cloud storage and merge with current settings", + "message": "Import dari storan awan dan gabungkan dengan tetapan semasa", "description": "tooltip" }, "cloudNoData": { @@ -1004,7 +1008,7 @@ "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": "Amaran! Ubah tetapan lanjutan ini dengan risiko anda sendiri.", "description": "A warning to users at the top of 'Advanced settings' page" }, "genericSubmit": { @@ -1012,11 +1016,11 @@ "description": "for generic 'Submit' buttons" }, "genericApplyChanges": { - "message": "Apply changes", + "message": "Terapkan perubahan", "description": "for generic 'Apply changes' buttons" }, "genericRevert": { - "message": "Revert", + "message": "membalikkan", "description": "for generic 'Revert' buttons" }, "genericBytes": { @@ -1024,31 +1028,31 @@ "description": "" }, "contextMenuTemporarilyAllowLargeMediaElements": { - "message": "Temporarily allow large media elements", + "message": "Biarkan sementara elemen media besar", "description": "A context menu entry, present when large media elements have been blocked on the current site" }, "shortcutCapturePlaceholder": { - "message": "Type a shortcut", + "message": "Taipkan jalan pintas", "description": "Placeholder string for input field used to capture a keyboard shortcut" }, "genericMergeViewScrollLock": { - "message": "Toggle locked scrolling", + "message": "Togol tatal terkunci", "description": "Tooltip for the button used to lock scrolling between the views in the 'My rules' pane" }, "genericCopyToClipboard": { - "message": "Copy to clipboard", + "message": "Salin ke papan keratan", "description": "Label for buttons used to copy something to the clipboard" }, "toggleBlockingProfile": { - "message": "Toggle blocking profile", + "message": "Togol profil penyekat", "description": "Label for keyboard shortcut used to toggle blocking profile" }, "relaxBlockingMode": { - "message": "Relax blocking mode", + "message": "Tenang mod menyekat", "description": "Label for keyboard shortcut used to relax blocking mode (meant to replace 'Toggle blocking profile')" }, "storageUsed": { - "message": "Storage used: {{value}} {{unit}}", + "message": "Storan yang digunakan: {{value}} {{unit}}", "description": " In Setting pane, renders as (example): Storage used: 13.2 MB" }, "KB": { @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Klik untuk memuatkan", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/nb/messages.json b/src/_locales/nb/messages.json index 779be73930a0e..99fb5430a947c 100644 --- a/src/_locales/nb/messages.json +++ b/src/_locales/nb/messages.json @@ -671,6 +671,10 @@ "message": "tillatt", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "endret", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "førstepart", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Klikk for å laste", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/nl/messages.json b/src/_locales/nl/messages.json index 9864039f8dc83..f97574f00ee90 100644 --- a/src/_locales/nl/messages.json +++ b/src/_locales/nl/messages.json @@ -300,7 +300,7 @@ "description": "An entry in the browser's contextual menu" }, "settingsCollapseBlockedPrompt": { - "message": "Tijdelijke aanduidingen van geblokkeerde elementen verbergen", + "message": "Aanduidingen van geblokkeerde elementen verbergen", "description": "English: Hide placeholders of blocked elements" }, "settingsIconBadgePrompt": { @@ -312,7 +312,7 @@ "description": "A checkbox in the Settings pane" }, "settingsContextMenuPrompt": { - "message": "Waar mogelijk gebruikmaken van het contextmenu", + "message": "Contextmenu gebruiken waar mogelijk", "description": "English: Make use of context menu where appropriate" }, "settingsColorBlindPrompt": { @@ -671,6 +671,10 @@ "message": "toegestaan", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "aangepast", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "huidige domein", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Klik om te laden", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/oc/messages.json b/src/_locales/oc/messages.json index 61e2d225d31a4..221e5e05b484f 100644 --- a/src/_locales/oc/messages.json +++ b/src/_locales/oc/messages.json @@ -671,6 +671,10 @@ "message": "allowed", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1st-party", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/pl/messages.json b/src/_locales/pl/messages.json index 9bdf0cbaa876c..51041edd82cf6 100644 --- a/src/_locales/pl/messages.json +++ b/src/_locales/pl/messages.json @@ -671,6 +671,10 @@ "message": "dozwolone", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "zmodyfikowane", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "własna domena", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Kliknij, aby załadować", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Ten wpis musi być ostatni", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/pt_BR/messages.json b/src/_locales/pt_BR/messages.json index fd0a5673c4987..f7e6c29f7e095 100644 --- a/src/_locales/pt_BR/messages.json +++ b/src/_locales/pt_BR/messages.json @@ -671,6 +671,10 @@ "message": "permitido", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modificado", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "primário", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Clique para carregar", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Esta entrada deve ser a última", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/pt_PT/messages.json b/src/_locales/pt_PT/messages.json index e5e2057fbb194..26708e2d9506b 100644 --- a/src/_locales/pt_PT/messages.json +++ b/src/_locales/pt_PT/messages.json @@ -660,7 +660,7 @@ "description": "A keyword in the built-in row filtering expression" }, "loggerRowFiltererBuiltinEventful": { - "message": "importante", + "message": "eventful", "description": "A keyword in the built-in row filtering expression: all items corresponding to uBO doing something (blocked, allowed, redirected, etc.)" }, "loggerRowFiltererBuiltinBlocked": { @@ -671,6 +671,10 @@ "message": "permitido", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modificado", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "primeiro", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Clique para carregar", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Esta entrada deve ser a última", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/ro/messages.json b/src/_locales/ro/messages.json index 895d046067206..c42d656cef68f 100644 --- a/src/_locales/ro/messages.json +++ b/src/_locales/ro/messages.json @@ -671,6 +671,10 @@ "message": "permis", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modificat", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "primare", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Apasă pentru a încărca", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Aceasta intrare trebuie sa fie ultima", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/ru/messages.json b/src/_locales/ru/messages.json index 703a546617bdf..475b149b8e5e0 100644 --- a/src/_locales/ru/messages.json +++ b/src/_locales/ru/messages.json @@ -671,6 +671,10 @@ "message": "allowed", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "модифицировано", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1st-party", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "ГБ", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Нажмите, чтобы загрузить", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Эта запись должна быть последней", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/sk/messages.json b/src/_locales/sk/messages.json index 0e233f770cb9c..27a03df1aabe0 100644 --- a/src/_locales/sk/messages.json +++ b/src/_locales/sk/messages.json @@ -671,6 +671,10 @@ "message": "povolené", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "zmenené", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "Z prvej strany", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Kliknite pre načítanie", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/sl/messages.json b/src/_locales/sl/messages.json index 8f567fcb21e86..1ba40e23781a2 100644 --- a/src/_locales/sl/messages.json +++ b/src/_locales/sl/messages.json @@ -671,6 +671,10 @@ "message": "dovoljeno", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "spremenjeno", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1. osebni", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Kliknite za prikaz", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/sq/messages.json b/src/_locales/sq/messages.json index 13710fdba4131..9c25751798cbe 100644 --- a/src/_locales/sq/messages.json +++ b/src/_locales/sq/messages.json @@ -304,7 +304,7 @@ "description": "English: Hide placeholders of blocked elements" }, "settingsIconBadgePrompt": { - "message": "Tregoj te ikona numrin e kërkesave të refuzuara", + "message": "Shfaq te ikona numrin e kërkesave të refuzuara", "description": "English: Show the number of blocked requests on the icon" }, "settingsTooltipsPrompt": { @@ -484,7 +484,7 @@ "description": "used as a tooltip for error icon beside a list" }, "1pFormatHint": { - "message": "Një filtër për rresht. Filtri mund të jetë thjesht emri i një hosti ose i ngjashëm me ata që përdor Adblock Plus. Nuk do të merren parasysh rreshtat që fillojnë me !.", + "message": "Një filtër për rresht. Filtri mund të jetë thjesht emri i një hosti ose i ngjashëm me ata që përdor EasyList. Nuk do të merren parasysh rreshtat që fillojnë me !.", "description": "Short information about how to create custom filters" }, "1pImport": { @@ -556,7 +556,7 @@ "description": "English: label for sort option." }, "rulesSortByType": { - "message": "Tipi i rregullit", + "message": "Lloji i rregullit", "description": "English: a sort option for list of rules." }, "rulesSortBySource": { @@ -671,6 +671,10 @@ "message": "të autorizuara", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "palët kryesore", "description": "A keyword in the built-in row filtering expression" @@ -904,11 +908,11 @@ "description": "English: Network error: {{msg}}" }, "subscriberConfirm": { - "message": "uBlock₀: Të shtohet adresa në listën e filtrave tuaj?\n\nTitulli: \"{{title}}\"\nURL: {{url}}", + "message": "Të shtohet adresa në listën e personalizuar të filtrave?\n\nTitulli: \"{{title}}\"\nURL: {{url}}", "description": "No longer used" }, "subscribeButton": { - "message": "Subscribe", + "message": "Abonohem", "description": "For the button used to subscribe to a filter list" }, "elapsedOneMinuteAgo": { @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Klikoni për ta hapur", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/sr/messages.json b/src/_locales/sr/messages.json index 2f47b84eb7444..b74cd994a6612 100644 --- a/src/_locales/sr/messages.json +++ b/src/_locales/sr/messages.json @@ -671,6 +671,10 @@ "message": "дозвољено", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "измењено", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "прве стране", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Кликните за учитавање", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/sv/messages.json b/src/_locales/sv/messages.json index 3e1ec8192730a..887e773239f15 100644 --- a/src/_locales/sv/messages.json +++ b/src/_locales/sv/messages.json @@ -671,6 +671,10 @@ "message": "tillåten", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "ändrad", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "Förstapart", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Klicka för att ladda", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/ta/messages.json b/src/_locales/ta/messages.json index 1359e299d055d..53819f715ee00 100644 --- a/src/_locales/ta/messages.json +++ b/src/_locales/ta/messages.json @@ -671,6 +671,10 @@ "message": "அனுமதிக்கப்படுகிறது", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "மாற்றப்பட்டது", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "முதல் கட்சி", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "ஏற்ற கிளிக் செய்க", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/te/messages.json b/src/_locales/te/messages.json index 1b15f5ebd705e..2693566d9bc1c 100644 --- a/src/_locales/te/messages.json +++ b/src/_locales/te/messages.json @@ -671,6 +671,10 @@ "message": "అనుమతించబడింది", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "సవరించబడింది", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "మొదటి పార్టీ", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "జీబీ", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "లోడ్ చేయడానికి క్లిక్ చేయండి", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "ఇది అంతిమంగా వుండాల్సిన నమోదు", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/th/messages.json b/src/_locales/th/messages.json index b9e944112706e..f650e2e78803f 100644 --- a/src/_locales/th/messages.json +++ b/src/_locales/th/messages.json @@ -671,6 +671,10 @@ "message": "allowed", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1st-party", "description": "A keyword in the built-in row filtering expression" @@ -852,7 +856,7 @@ "description": "English: Source code (GPLv3)" }, "aboutContributors": { - "message": "Contributors", + "message": "ผู้มีส่วนร่วม", "description": "English: Contributors" }, "aboutSourceCode": { @@ -860,7 +864,7 @@ "description": "Link text to source code repo" }, "aboutTranslations": { - "message": "Translations", + "message": "การแปลภาษา", "description": "Link text to translations repo" }, "aboutFilterLists": { @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "คลิกเพื่อโหลด", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/tr/messages.json b/src/_locales/tr/messages.json index 358170239fcb2..70473965d5e2b 100644 --- a/src/_locales/tr/messages.json +++ b/src/_locales/tr/messages.json @@ -671,6 +671,10 @@ "message": "izinli", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "düzenlendi", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "1. taraf", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Yüklemek için tıkla", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Bu girdi en sonda olmalıdır", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/uk/messages.json b/src/_locales/uk/messages.json index 93bd63c1ffdc7..e8aa6decfedf3 100644 --- a/src/_locales/uk/messages.json +++ b/src/_locales/uk/messages.json @@ -671,6 +671,10 @@ "message": "дозволений", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "основний", "description": "A keyword in the built-in row filtering expression" @@ -856,7 +860,7 @@ "description": "English: Contributors" }, "aboutSourceCode": { - "message": "Джерельний код", + "message": "Вихідний код", "description": "Link text to source code repo" }, "aboutTranslations": { @@ -1063,6 +1067,10 @@ "message": "ГБ", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Натисніть, щоб завантажити", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Цей запис має бути останнім", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/ur/messages.json b/src/_locales/ur/messages.json index 9844284ee65dc..c07c6e839c277 100644 --- a/src/_locales/ur/messages.json +++ b/src/_locales/ur/messages.json @@ -671,6 +671,10 @@ "message": "اجازت والے", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "فریق اول", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "This entry must be the last one", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/vi/messages.json b/src/_locales/vi/messages.json index e78b56da57512..4b0873ad0bb23 100644 --- a/src/_locales/vi/messages.json +++ b/src/_locales/vi/messages.json @@ -671,6 +671,10 @@ "message": "được phép", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "modified", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "Bên thứ nhất", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "Click to load", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "Đây là mục cuối", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/zh_CN/messages.json b/src/_locales/zh_CN/messages.json index 42d917cc60e97..30aed228f69f2 100644 --- a/src/_locales/zh_CN/messages.json +++ b/src/_locales/zh_CN/messages.json @@ -671,6 +671,10 @@ "message": "已允许", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "已修改", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "第一方", "description": "A keyword in the built-in row filtering expression" @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "单击以加载", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "此条目必须是最后一个", "description": "so we dont need to deal with comma for last entry" diff --git a/src/_locales/zh_TW/messages.json b/src/_locales/zh_TW/messages.json index dc824f24262a1..14c9bd78ff880 100644 --- a/src/_locales/zh_TW/messages.json +++ b/src/_locales/zh_TW/messages.json @@ -40,7 +40,7 @@ "description": "appears as tab name in dashboard" }, "whitelistPageName": { - "message": "白名單", + "message": "信任名單", "description": "appears as tab name in dashboard" }, "shortcutsPageName": { @@ -156,7 +156,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": { @@ -188,7 +188,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": { @@ -236,7 +236,7 @@ "description": "" }, "popup3pPassiveRulePrompt": { - "message": "第三方階層式樣式表 (CSS)/圖片", + "message": "第三方 CSS 樣式表/圖片", "description": "" }, "popupInlineScriptRulePrompt": { @@ -296,7 +296,7 @@ "description": "English: Click, Ctrl-click" }, "pickerContextMenuEntry": { - "message": "阻擋元素", + "message": "阻擋元素…", "description": "An entry in the browser's contextual menu" }, "settingsCollapseBlockedPrompt": { @@ -312,7 +312,7 @@ "description": "A checkbox in the Settings pane" }, "settingsContextMenuPrompt": { - "message": "使用階層式內容功能表", + "message": "將 uBlock Origin 加入右鍵選單", "description": "English: Make use of context menu where appropriate" }, "settingsColorBlindPrompt": { @@ -352,7 +352,7 @@ "description": "" }, "settingsNoCosmeticFilteringPrompt": { - "message": "停用網頁元素過濾", + "message": "停用元素隱藏過濾規則", "description": "" }, "settingsNoLargeMediaPrompt": { @@ -404,7 +404,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": { @@ -412,7 +412,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." }, "3pListsOfBlockedHostsHeader": { @@ -456,7 +456,7 @@ "description": "English: Custom" }, "3pImport": { - "message": "匯入⋯", + "message": "匯入…", "description": "The label for the checkbox used to import external filter lists" }, "3pExternalListsHint": { @@ -464,7 +464,7 @@ "description": "Short information about how to use the textarea to import external filter lists by URL" }, "3pExternalListObsolete": { - "message": "过久未更新。", + "message": "過久未更新。", "description": "used as a tooltip for the out-of-date icon beside a list" }, "3pViewContent": { @@ -568,7 +568,7 @@ "description": "English: a sort option for list of rules." }, "whitelistPrompt": { - "message": "列表裡的主機名稱將被 uBlock₀ 停用。每行一個規則。無效的主機名稱將被忽略掉。", + "message": "信任名單中的規則適用的頁面不會被 uBlock Origin 過濾或阻擋。每行一個規則。無效的規則將被忽略。", "description": "The name of the trusted sites pane." }, "whitelistImport": { @@ -580,7 +580,7 @@ "description": "English: Export" }, "whitelistExportFilename": { - "message": "我的-ublock-白名單_{{datetime}}.txt", + "message": "my-ublock-trusted-sites_{{datetime}}.txt", "description": "The default filename to use for import/export purpose" }, "whitelistApply": { @@ -620,7 +620,7 @@ "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": { @@ -636,7 +636,7 @@ "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": { @@ -671,6 +671,10 @@ "message": "已允許", "description": "A keyword in the built-in row filtering expression" }, + "loggerRowFiltererBuiltinModified": { + "message": "已修改", + "description": "A keyword in the built-in row filtering expression" + }, "loggerRowFiltererBuiltin1p": { "message": "第一方", "description": "A keyword in the built-in row filtering expression" @@ -728,7 +732,7 @@ "description": "Label for the type selector" }, "loggerStaticFilteringHeader": { - "message": "靜態過濾規則", + "message": "靜態過濾", "description": "Small header to identify the static filtering section" }, "loggerStaticFilteringSentence": { @@ -772,11 +776,11 @@ "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": { @@ -784,7 +788,7 @@ "description": "A logger setting" }, "loggerSettingPerTabMaxLoads": { - "message": "每個分頁最多保留 {{input}} 次內容加載產生的記錄", + "message": "每個分頁最多保留 {{input}} 次重新載入該頁所產生的記錄", "description": "A logger setting" }, "loggerSettingPerTabMaxEntries": { @@ -904,7 +908,7 @@ "description": "English: Network error: {{msg}}" }, "subscriberConfirm": { - "message": "uBlock₀:確定要新增下列網址至自訂過濾規則清單?\n\n標題:「{{title}}」\n網址:{{url}}", + "message": "確定要新增下列網址至自訂過濾規則清單?\n\n標題:「{{title}}」\n網址:{{url}}", "description": "No longer used" }, "subscribeButton": { @@ -948,7 +952,7 @@ "description": "Firefox-specific: appears as 'uBlock₀ (off)'" }, "docblockedPrompt1": { - "message": "uBlock₀ 已防止下列的頁面載入:", + "message": "uBlock Origin 已防止下列頁面載入:", "description": "Used in the strict-blocking page" }, "docblockedPrompt2": { @@ -1028,7 +1032,7 @@ "description": "A context menu entry, present when large media elements have been blocked on the current site" }, "shortcutCapturePlaceholder": { - "message": "輸入捷徑", + "message": "輸入快捷鍵", "description": "Placeholder string for input field used to capture a keyboard shortcut" }, "genericMergeViewScrollLock": { @@ -1040,7 +1044,7 @@ "description": "Label for buttons used to copy something to the clipboard" }, "toggleBlockingProfile": { - "message": "切換封鎖設定檔", + "message": "開閉封鎖設定檔", "description": "Label for keyboard shortcut used to toggle blocking profile" }, "relaxBlockingMode": { @@ -1063,6 +1067,10 @@ "message": "GB", "description": "short for 'gigabytes'" }, + "clickToLoad": { + "message": "點擊以載入", + "description": "Message used in frame placeholders" + }, "dummy": { "message": "此條目須為最後一個", "description": "so we dont need to deal with comma for last entry" diff --git a/src/about.html b/src/about.html index f3cda3c6b3687..a76287c17eea0 100644 --- a/src/about.html +++ b/src/about.html @@ -28,7 +28,7 @@

 
-
+
 
diff --git a/src/css/3p-filters.css b/src/css/3p-filters.css index d893a13d2da52..5c57470b6ff2a 100644 --- a/src/css/3p-filters.css +++ b/src/css/3p-filters.css @@ -1,7 +1,17 @@ @keyframes spin { - 0% { transform: rotate(0deg); -webkit-transform: rotate(0deg); } - 100% { transform: rotate(360deg); -webkit-transform: rotate(360deg); } - } + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} +body { + margin-bottom: 6rem; +} +#actions { + background-color: var(--default-surface); + padding: var(--default-gap-small) 0 var(--default-gap-xsmall) 0; + position: sticky; + top: 0; + z-index: 10; +} /*ADN*/ #options .li:nth-child(2), #options .li:nth-child(3){ display: none; diff --git a/src/css/about.css b/src/css/about.css index f2dac7a4d319e..7939540fdcb43 100644 --- a/src/css/about.css +++ b/src/css/about.css @@ -1,4 +1,5 @@ body { + margin-bottom: 6rem; padding: 0 0.5em; font-size: 20px; font-family: bebas_neue,sans-serif; @@ -23,6 +24,7 @@ body { ul { margin-__MSG_@@bidi_start_edge__: 1em; } + .entries { margin: 0.5em 0; margin-inline-start: 2em; diff --git a/src/css/click2load.css b/src/css/click2load.css new file mode 100644 index 0000000000000..cf445db785225 --- /dev/null +++ b/src/css/click2load.css @@ -0,0 +1,52 @@ +/** + 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 +*/ + +body { + align-items: center; + background-color: var(--default-surface); + border: 1px solid var(--ubo-red); + box-sizing: border-box; + display: flex; + flex-direction: column; + padding: 0 2px; + position: relative; + } + +.logo { + left: 0; + padding: 2px 1px; + position: absolute; + top: 0; + } + +#frameURL { + font-family: monospace; + font-size: 90%; + overflow-y: auto; + word-break: break-all; + } +#frameURL > a { + font-size: 1rem; + } + +#clickToLoad { + cursor: default; + margin-bottom: 1em; + } diff --git a/src/css/cloud-ui.css b/src/css/cloud-ui.css index 02d28001dab0e..4944fda03cfcd 100644 --- a/src/css/cloud-ui.css +++ b/src/css/cloud-ui.css @@ -1,5 +1,5 @@ #cloudWidget { - background: url("../img/cloud.png") hsl(216, 100%, 93%); + background-color: var(--cloud-widget-surface); margin: 0.5em 0; min-width: max-content; position: relative; diff --git a/src/css/codemirror.css b/src/css/codemirror.css index d6a5ae1a0615b..4bd080e99ae73 100644 --- a/src/css/codemirror.css +++ b/src/css/codemirror.css @@ -5,11 +5,23 @@ position: relative; } .CodeMirror { + background-color: var(--default-surface); box-sizing: border-box; + color: var(--default-ink); flex-grow: 1; height: 100%; width: 100%; } +.CodeMirror-lines { + padding-bottom: 6rem; + } +.CodeMirror-gutters { + background-color: var(--cm-gutter-surface); + border-color: var(--cm-gutter-border); + } +.CodeMirror-linenumber { + color: var(--cm-gutter-ink); + } /* For when panels are used */ .codeMirrorContainer > div:not([class^="CodeMirror"]) { @@ -23,47 +35,78 @@ } /* CodeMirror theme overrides */ -.cm-s-default .cm-def {color: #4d4dff;} -.cm-s-default .cm-value { color: #e64d00; } -.cm-s-default .cm-comment { color: #777; } -.cm-s-default .cm-keyword { color: #d208ff; } -.cm-s-default .cm-regex { - text-underline-position: under; - text-decoration-color: darkgray; - text-decoration-style: solid; - text-decoration-line: underline; +.CodeMirror-focused .CodeMirror-selected { + background: var(--cm-selection-surface); + color: var(--cm-selection-ink); + } +.CodeMirror-line::selection, +.CodeMirror-line > span::selection, +.CodeMirror-line > span > span::selection { + background: var(--cm-selection-surface); + color: var(--cm-selection-ink); + } + +.cm-s-default .cm-comment { + color: var(--sf-comment-ink); + } +.cm-s-default .cm-def { + color: var(--sf-def-ink); + } +.cm-s-default .cm-directive { + color: var(--sf-directive-ink); + font-weight: bold; } .cm-s-default .cm-error { color: inherit; } .cm-s-default .cm-error, .CodeMirror-linebackground.error { - background-color: #ff000016; - text-decoration: underline red; + background-color: var(--sf-error-surface); + text-decoration: underline var(--sf-error-ink); + text-underline-position: under; + } +.cm-s-default .cm-link { + text-decoration: none; + } +.cm-s-default .cm-link:hover { + color: var(--link-ink); + } +.cm-s-default .cm-keyword { + color: var(--sf-keyword-ink); + } +.cm-s-default .cm-regex { + text-underline-position: under; + text-decoration-color: var(--sf-regex-ink); + text-decoration-style: solid; + text-decoration-line: underline; + } +.cm-s-default .cm-tag { + color: var(--sf-tag-ink); + } +.cm-s-default .cm-value { color: var(--sf-value-ink); } +.cm-s-default .cm-variable { + color: var(--sf-variable-ink); + } +.cm-s-default .cm-warning { + text-decoration: underline var(--sf-warning-ink); text-underline-position: under; } - -.cm-directive { color: #333; font-weight: bold; } -.cm-staticext { color: #008; } -.cm-staticnetBlock { color: #800; } -.cm-staticnetAllow { color: #004f00; } -.cm-staticOpt { background-color: #777; font-weight: bold; } /* Rules */ .cm-s-default .cm-allowrule { - color: green; + color: var(--df-allow-ink); font-weight: bold; } .cm-s-default .cm-blockrule { - color: red; + color: var(--df-block-ink); font-weight: bold; } .cm-s-default .cm-nooprule { - color: darkslategray; + color: var(--df-noop-ink); font-weight: bold; } .cm-s-default .cm-sortkey { - color: #708; + color: var(--sf-keyword-ink); } div.CodeMirror span.CodeMirror-matchingbracket { @@ -77,7 +120,8 @@ div.CodeMirror span.CodeMirror-matchingbracket { .cm-search-widget { align-items: center; - background-color: var(--bg-code); + background-color: var(--cm-gutter-surface); + border-bottom: 1px solid var(--cm-gutter-border); cursor: default; direction: ltr; display: flex; @@ -94,14 +138,14 @@ div.CodeMirror span.CodeMirror-matchingbracket { flex-grow: 1; } .cm-search-widget .fa-icon { - fill: #888; + fill: var(--cm-gutter-ink); font-size: 140%; } .cm-search-widget .fa-icon:not(.fa-icon-ro):hover { fill: #000; } .cm-search-widget-input input { - border: 1px solid gray; + border: 1px solid var(--cm-gutter-ink); display: inline-flex; flex-grow: 1; max-width: 16em; @@ -124,9 +168,13 @@ div.CodeMirror span.CodeMirror-matchingbracket { display: none; } .cm-searching { + background-color: var(--cm-searching-surface) !important; border: 1px dotted black; } +.CodeMirror-merge { + border-color: var(--cm-gutter-border); + } .CodeMirror-merge-l-deleted { background-image: none; } @@ -135,10 +183,12 @@ div.CodeMirror span.CodeMirror-matchingbracket { } /* This probably needs to be added to CodeMirror repo */ .CodeMirror-merge-gap { + background-color: var(--cm-gutter-surface); + border-color: var(--cm-gutter-border); vertical-align: top; } .CodeMirror-merge-spacer { - background-color: var(--bg-code); + background-color: var(--cm-gutter-surface); } .CodeMirror-hints { diff --git a/src/css/common.css b/src/css/common.css index 538bb1e50cac4..c35f9f75665d6 100644 --- a/src/css/common.css +++ b/src/css/common.css @@ -583,7 +583,7 @@ code, .code { } hr { border: 0; - border-top: 1px solid var(--hor-separator-color); + border-top: 1px solid var(--hr-ink); margin: 1em 0; } .hiddenFileInput { diff --git a/src/css/document-blocked.css b/src/css/document-blocked.css index 38b92bb371873..7e402beec50cf 100644 --- a/src/css/document-blocked.css +++ b/src/css/document-blocked.css @@ -21,8 +21,6 @@ body { display: flex; flex-direction: column; - font-size: 14px; - line-height: 20px; padding: 40px; text-align: center; } diff --git a/src/css/epicker-ui.css b/src/css/epicker-ui.css index 8a5e04634650d..53552d94aa513 100644 --- a/src/css/epicker-ui.css +++ b/src/css/epicker-ui.css @@ -1,7 +1,7 @@ html#ublock0-epicker, #ublock0-epicker body { background: transparent; - color: black; + color: var(--default-ink); cursor: not-allowed; font: 12px sans-serif; height: 100vh; @@ -14,12 +14,13 @@ html#ublock0-epicker, } #ublock0-epicker aside { background-color: var(--default-surface); - border: 1px solid #aaa; + border: 1px solid var(--default-surface-border); bottom: 4px; box-sizing: border-box; cursor: default; display: none; - min-width: 24em; + max-width: 36rem; + min-width: 24rem; padding: 4px; position: fixed; right: 4px; @@ -28,18 +29,9 @@ html#ublock0-epicker, #ublock0-epicker.paused:not(.zap) aside { display: block; } -#ublock0-epicker ul, -#ublock0-epicker li, -#ublock0-epicker div { - display: block; -} #ublock0-epicker #toolbar { cursor: grab; display: flex; - justify-content: space-between; -} -#ublock0-epicker aside.moving #toolbar { - cursor: grabbing; } #ublock0-epicker ul { margin: 0.25em 0 0 0; @@ -71,6 +63,13 @@ html#ublock0-epicker, background-color: var(--button-preferred-surface); color: var(--button-preferred-ink); } +#ublock0-epicker #move { + cursor: grab; + flex-grow: 1; + } +#ublock0-epicker aside.moving #move { + cursor: grabbing; +} #ublock0-epicker section { border: 0; box-sizing: border-box; @@ -78,36 +77,31 @@ html#ublock0-epicker, width: 100%; } #ublock0-epicker section > div:first-child { - border: 1px solid #aaa; + border: 1px solid var(--default-surface-border); margin: 0; position: relative; } #ublock0-epicker section.invalidFilter > div:first-child { border-color: red; } -#ublock0-epicker section textarea { - background-color: #fff; +#ublock0-epicker section .codeMirrorContainer { border: none; box-sizing: border-box; - color: #000; font: 11px monospace; height: 8em; - margin: 0; - overflow: hidden; - overflow-y: auto; - padding: 2px 2px 1.2em 2px; - resize: none; + padding: 2px; width: 100%; - word-break: break-all; -} -#ublock0-epicker section textarea + div { - background-color: transparent; - bottom: 0; + } +.CodeMirror-lines, +.CodeMirror pre { + padding: 0; + } +.CodeMirror-vscrollbar { + z-index: 0; + } + +#ublock0-epicker section .resultsetWidgets { display: flex; - left: 0; - pointer-events: none; - position: absolute; - right: 0; } #resultsetModifiers { align-items: flex-end; @@ -126,12 +120,14 @@ html#ublock0-epicker, } .resultsetModifier > span { align-items: flex-end; - border-bottom: 2px solid white; display: flex; height: 100%; pointer-events: none; width: 100%; } +.resultsetModifier > span > span { + margin: 2px 0; + } .resultsetModifier > span > span:nth-of-type(1) { background-color: var(--checkbox-checked-ink); border-inline-end: 1px solid #aaa; @@ -195,7 +191,7 @@ html#ublock0-epicker, overflow: hidden; } #ublock0-epicker #candidateFilters { - max-height: 16em; + max-height: 14em; overflow-y: auto; } #ublock0-epicker #candidateFilters > li:first-of-type { @@ -225,7 +221,7 @@ html#ublock0-epicker, border: 1px dotted var(--blue-50); } #ublock0-epicker #candidateFilters .changeFilter li:hover { - background-color: white; + background-color: var(--default-surface-hover); } /** diff --git a/src/css/logger-ui-inspector.css b/src/css/logger-ui-inspector.css index e7d45e2868e36..acfd5c5638c4d 100644 --- a/src/css/logger-ui-inspector.css +++ b/src/css/logger-ui-inspector.css @@ -14,7 +14,7 @@ padding-left: 0.5em; } #domInspector ul { - background-color: #fff; + background-color: var(--default-surface); margin: 0; padding-left: 1em; } @@ -37,7 +37,7 @@ color: #aaa; } #domInspector li > span:first-child { - color: #000; + color: var(--default-ink); cursor: default; font-size: 1rem; margin-right: 0; diff --git a/src/css/logger-ui.css b/src/css/logger-ui.css index 6ecc9766cd2e5..47751d85ad6da 100644 --- a/src/css/logger-ui.css +++ b/src/css/logger-ui.css @@ -15,7 +15,7 @@ textarea { position: relative; } .permatoolbar { - background-color: white; + background-color: var(--default-surface); border: 0; box-sizing: border-box; display: flex; @@ -37,7 +37,7 @@ textarea { fill: #5F9EA0; } .permatoolbar .button:hover { - background-color: #eee; + background-color: var(--default-surface-hover); } #pageSelector { min-width: 10em; @@ -165,7 +165,7 @@ body.colorBlind #netInspector tr.allowed { transform: scaleY(1); } #netInspector #filterExprPicker { - background-color: white; + background-color: var(--default-surface); border: 1px solid gray; display: none; position: absolute; @@ -490,7 +490,7 @@ body.colorBlind #netFilteringDialog > .panes > .details > div[data-status="2"] b } #popupContainer { - background: white; + background-color: var(--default-surface); border: 1px solid gray; bottom: 0; display: none; @@ -526,7 +526,7 @@ body.colorBlind #netFilteringDialog > .panes > .details > div[data-status="2"] b position: relative; } #modalOverlay > div > div:nth-of-type(1) { - background-color: white; + background-color: var(--default-surface); border: 0; box-sizing: border-box; padding: 1em; @@ -535,13 +535,13 @@ body.colorBlind #netFilteringDialog > .panes > .details > div[data-status="2"] b width: 90vw; } #modalOverlay > div > div:nth-of-type(2) { - stroke: #000; + stroke: var(--default-ink); stroke-width: 3px; position: absolute; width: 1.6em; height: 1.6em; bottom: calc(100% + 2px); - background-color: white; + background-color: var(--default-surface); } body[dir="ltr"] #modalOverlay > div > div:nth-of-type(2) { right: 0; @@ -550,7 +550,7 @@ body[dir="rtl"] #modalOverlay > div > div:nth-of-type(2) { left: 0; } #modalOverlay > div > div:nth-of-type(2):hover { - background-color: #eee; + background-color: var(--default-surface-hover); } #modalOverlay > div > div:nth-of-type(2) > * { pointer-events: none; diff --git a/src/css/popup-fenix.css b/src/css/popup-fenix.css index 597db50cc0d99..d4c897f0ee826 100644 --- a/src/css/popup-fenix.css +++ b/src/css/popup-fenix.css @@ -24,7 +24,8 @@ opacity: 0; } a { - color: inherit; + color: var(--default-ink); + fill: var(--default-ink); text-decoration: none; } :focus { @@ -48,7 +49,7 @@ a { } hr { border: 0; - border-top: 1px solid #e3e2e3; + border-top: 1px solid var(--hr-ink); margin: 0; padding: 0; } @@ -554,6 +555,14 @@ body:not([data-more~="e"]) [data-more="e"] { display: none; } +/* popup-in-tab mode, useful for screenshots */ +:root.desktop.intab body { + overflow: auto; + } +:root.desktop.intab #firewall { + max-height: none; + } + /* horizontally-constrained viewport */ :root.portrait body { overflow-y: auto; diff --git a/src/css/settings.css b/src/css/settings.css index 3320be80d7a02..c92da0b9f4c43 100644 --- a/src/css/settings.css +++ b/src/css/settings.css @@ -5,11 +5,19 @@ ul { padding-left: 1em; padding-right: 0; - } +} + body { + margin-bottom: 6rem; +} +.synopsis { + font-size: 90%; +} +[href="advanced-settings.html"] { + display: none; +} body[dir="rtl"] ul { padding-left: 0; padding-right: 1em; - } } ul#userSettings { diff --git a/src/css/themes/default.css b/src/css/themes/default.css index b4d02a22cd1f8..6f385e82f03d5 100644 --- a/src/css/themes/default.css +++ b/src/css/themes/default.css @@ -12,10 +12,14 @@ */ :root { --blue-10: #80ebff; + --blue-40: #0090ed; --blue-50: #0060df; --blue-60: #0250bb; + --dark-gray-10: #52525e; --dark-gray-30: #42414d; + --dark-gray-40: #3a3944; --dark-gray-50: #32313c; + --dark-gray-70: #23222b; --dark-gray-80: #1c1b22; --dark-gray-90: #15141a; --ink-20: #312a65; @@ -29,18 +33,23 @@ --light-gray-10-a12: #f9f9fb1f; --light-gray-10-a16: #f9f9fb29; --light-gray-20: #f0f0f4; + --light-gray-25: #e8e8ed; --light-gray-30: #e0e0e6; --light-gray-30-a50: #e0e0e680; --light-gray-40: #cfcfd8; --light-gray-50: #bfbfc9; --light-gray-60: #afafba; --light-gray-70: #9f9fad; + --light-gray-80: #8f8f9e; --light-gray-90: #80808f; + --orange-80: #9e280b; + --purple-60: #952bb9; --red-60: #e22850; --violet-40: #ab71ff; --violet-60: #7542e5; --violet-70: #592acb; --violet-80: #45278d; + --yellow-10: #ffff98; --yellow-30: #ffd567; --yellow-40: #ffbd4f; --yellow-50: #ffa436; @@ -66,10 +75,13 @@ :root { --font-size: 14px; + --ubo-red: #800000; + --default-ink: var(--ink-80); --default-ink-a4: var(--ink-80-a4); --default-ink-a50: var(--ink-80-a50); --default-surface: var(--light-gray-10); + --default-surface-border: var(--light-gray-70); --default-surface-hover: var(--light-gray-30-a50); --bg-1: hsla(240, 20%, 98%, 1); @@ -93,8 +105,6 @@ --fieldset-header-surface: transparent; --fieldset-header-ink: var(--ink-20); - --hor-separator-color: var(--light-gray-30); - --button-surface: var(--light-gray-30); --button-ink: #0076FF; /* AdNauseam */ --button-surface-hover: var(--light-gray-40); @@ -159,6 +169,39 @@ --bg-popup-cell-block-own: hsla(0, 100%, 40%, 1); --bg-popup-cell-label-mixed: hsla(45, 100%, 38%, 1); --popup-icon-x-ink: var(--red-60); + + /* horizontal line separator */ + --hr-ink: var(--light-gray-30); + + /* cloud widget */ + --cloud-widget-surface: var(--light-gray-20); + + /* codemirror */ + --cm-gutter-border: var(--light-gray-40); + --cm-gutter-ink: var(--light-gray-90); + --cm-gutter-surface: var(--light-gray-25); + --cm-selection-surface: #d7d4f0; + --cm-selection-ink: var(--default-ink); + --cm-searching-surface: #ffff0066; + + /* syntax highlight: static filtering */ + --sf-comment-ink: var(--light-gray-90); + --sf-def-ink: #0000ff; + --sf-directive-ink: var(--dark-gray-40); + --sf-error-ink: #ff0000; + --sf-error-surface: #ff000016; + --sf-keyword-ink: var(--purple-60); + --sf-regex-ink: var(--light-gray-60); + --sf-tag-ink: #117700; + --sf-value-ink: var(--orange-80); + --sf-variable-ink: var(--default-ink); + --sf-warning-ink: var(--yellow-50); + + /* syntax highlight: dynamic filtering */ + --df-allow-ink: #117700; + --df-block-ink: #ff0000; + --df-noop-ink: var(--dark-gray-10); + --df-key-ink: var(--violet-70); } /** @@ -202,6 +245,110 @@ } :root.dark { + --default-ink: var(--light-gray-10); + --default-ink-a4: var(--light-gray-10-a4); + --default-ink-a50: var(--light-gray-30-a50); + --default-surface: var(--dark-gray-90); + --default-surface-hover: var(--dark-gray-50); + --bg-1: hsla(250, 13%, 9%, 1); + --bg-1-border: hsla(250, 13%, 16%, 1); + --bg-overlay-50: #0008; + --bg-code: hsla(0, 2%, 0%, 0.8); + --fg-0-80: hsla(0, 0%, 53%, 0.8); + --fg-0-70: hsla(0, 0%, 53%, 0.7); + --fg-0-60: hsla(0, 0%, 53%, 0.6); + --fg-0-50: hsla(0, 0%, 53%, 0.5); + --fg-0-40: hsla(0, 0%, 53%, 0.4); + --fg-0-30: hsla(0, 0%, 53%, 0.3); + --fg-0-20: hsla(0, 0%, 53%, 0.2); + --link-ink: #bb86fc; + --fieldset-header-surface: transparent; + --fieldset-header-ink: var(--light-gray-30); + --hr-ink: var(--dark-gray-50); + --button-surface: var(--light-gray-10-a12); + --button-ink: var(--default-ink); + --button-surface-hover: var(--light-gray-10-a12); + --button-active-surface: var(--light-gray-70); + --button-important-surface: var(--dark-gray-30); + --button-important-surface-hover: var(--light-gray-60); + --button-disabled-filter: opacity(38%); + --button-disabled-surface: var(--dark-gray-50); + --button-disabled-ink: var(--light-gray-30-a50); + --button-preferred-surface: var(--dark-gray-50); + --button-preferred-ink: var(--light-gray-70); + --checkbox-size: calc(var(--font-size) + 2px); + --checkbox-ink: var(--default-ink); + --checkbox-checked-ink: #bb86fc; + /*--select-surface:*/ + --bg-transient-notice: var(--dark-gray-50); + --dashboard-bar-shadow: 0px 0px 0px 1px var(--default-ink-a4); + --dashboard-tab-active-ink: #bb86fc; + --dashboard-tab-surface-hover: var(--default-surface-hover); + --fg-icon-info-lvl-0-dimmed: #888; + --fg-icon-info-lvl-0: inherit; + --fg-icon-info-lvl-1-dimmed: hsla(258, 57%, 35%, 1); + --fg-icon-info-lvl-1: hsla(258, 66%, 48%, 1); + --info-lvl-2-ink: var(--yellow-50); + --info-lvl-2-ink-hover: var(--yellow-60); + --fg-icon-info-lvl-3-dimmed: hsla(16, 100%, 50%, 0.5); + --fg-icon-info-lvl-3: hsla(16, 100%, 50%, 1); + --fg-icon-info-lvl-4-dimmed: hsla(0, 100%, 35%, 0.5); + --fg-icon-info-lvl-4: hsla(0, 100%, 35%, 1); + --large-icon-info-lvl-2: hsla(41, 100%, 47%, 1); + --bg-tooltip: var(--dark-gray-50); + --fg-tooltip: var(--light-gray-30); + --bg-popup-cell-1: var(--dark-gray-50); + --popup-power-disabled-ink: var(--light-gray-60); + --popup-power-ink-hover: var(--dark-gray-30); + --bg-popup-cell-2: var(--dark-gray-50); + --bg-popup-cell-label-filter: opacity(40%); + --fg-popup-cell-cname: hsla(0, 0%, 53%, 0.3); + --bg-popup-cell-allow: hsla(120, 40%, 75%, 1); + --bg-popup-cell-allow-own: hsla(120, 100%, 30%, 1); + --bg-popup-cell-noop: hsla(0, 0%, 75%, 1); + --bg-popup-cell-noop-own: hsla(0, 0%, 45%, 1); + --bg-popup-cell-block: hsla(0, 50%, 80%, 1); + --bg-popup-cell-block-own: hsla(0, 100%, 40%, 1); + --bg-popup-cell-label-mixed: hsla(45, 100%, 38%, 1); + --popup-icon-x-ink: #e22850; + + /* Need to set colors in forms.css for moz-field stuffz + -moz-FieldText: #888888 !important; change from these names to either HEX value or variables. default-ink + -moz-Field: #15141a !important; var would be var(--dark-gray-90) hex value might be easiest though. + /* TO DO + 1. Epicker window box color Variables needed; + #ublock0-epicker aside + background-color: var(--dark-gray-90) + outer border: var(--dark-gray-90) + inner order: var ( + color: #999999a0 + html#ublock0-epicker, #ublock0-epicker body + background: transparent !important; + color: #777 !important; + + 2. CodeMirror (my filters and Whitelist) ADVANCED SETTINGS (background and color need variables) + .CodeMirror background: (currenty set to white) need a var + my Rules tab + codemirror panes CodeMirror-merge-pane CodeMirror-merge-left + CodeMirror-merge-pane CodeMirror-merge-editor CodeMirror-merge-pane-rightmost + ***** file used is codemirror.css ********* + + 3. #cloudWidget background (linked to img) background is hsl - would be better if we had a background color instead of hsl. + ***** file used is cloud-ui.css ******** + 4. Logger UI screen. .permatoolbar, modalOverlayContainer : background-color; + headers background-color, color border-color + #netFilteringDialog > div.panes > .dynamic .entry background-color: border-bottom: ; + #netFilteringDialog > div.panes > .dynamic .entry > .action > .allow .noop .block + background-color. + #modalOverlayClose stoke: background-color + ****** file used is logger-ui.css ******* + *//* + 5. Seperator bar - element/selector is hr in common.css a variable is assigned. popup-fenix.css + border-top - assigned HEX of #e3e2e3 variable should be assinged like in common.css + var(--hor-separator-color) + 6. .rulesetTools border color needs a variable + **** popup-fenix.css ***** +*/ } :root.dark.colorBlind { diff --git a/src/document-blocked.html b/src/document-blocked.html index fc3db9eab195b..87120c85a6d81 100644 --- a/src/document-blocked.html +++ b/src/document-blocked.html @@ -4,13 +4,13 @@ - - - - + + + + -
exclamation-triangle
+
exclamation-triangle

@@ -51,7 +51,7 @@   + -->
diff --git a/src/js/1p-filters.js b/src/js/1p-filters.js index 859fe72336006..adf179f8825ee 100644 --- a/src/js/1p-filters.js +++ b/src/js/1p-filters.js @@ -42,7 +42,9 @@ const cmEditor = new CodeMirror(document.getElementById('userFilters'), { lineWrapping: true, matchBrackets: true, maxScanLines: 1, - styleActiveLine: true, + styleActiveLine: { + nonEmpty: true, + }, }); uBlockDashboard.patchCodeMirrorEditor(cmEditor); @@ -55,12 +57,24 @@ vAPI.messaging.send('dashboard', { if ( mode.setHints instanceof Function ) { mode.setHints(response); } + mode.parser.expertMode = response.expertMode !== false; }); let cachedUserFilters = ''; /******************************************************************************/ +const getEditorText = function() { + const text = cmEditor.getValue().replace(/\s+$/, ''); + return text === '' ? text : text + '\n'; +}; + +const setEditorText = function(text) { + cmEditor.setValue(text.replace(/\s+$/, '') + '\n\n'); +}; + +/******************************************************************************/ + // This is to give a visual hint that the content of user blacklist has changed. const userFiltersChanged = function(changed) { @@ -81,10 +95,7 @@ const renderUserFilters = async function() { let content = details.content.trim(); cachedUserFilters = content; - if ( content.length !== 0 ) { - content += '\n'; - } - cmEditor.setValue(content); + setEditorText(content); userFiltersChanged(false); }; @@ -115,13 +126,10 @@ const handleImportFilePicker = function() { const fileReaderOnLoadHandler = function() { let content = abpImporter(this.result); - content = uBlockDashboard.mergeNewLines( - cmEditor.getValue().trim(), - content - ); + content = uBlockDashboard.mergeNewLines(getEditorText(), content); cmEditor.operation(( ) => { const cmPos = cmEditor.getCursor(); - cmEditor.setValue(`${content}\n`); + setEditorText(content); cmEditor.setCursor(cmPos); cmEditor.focus(); }); @@ -148,7 +156,7 @@ const startImportFilePicker = function() { /******************************************************************************/ const exportUserFiltersToFile = function() { - const val = cmEditor.getValue().trim(); + const val = getEditorText(); if ( val === '' ) { return; } const filename = vAPI.i18n('1pExportFilename') .replace('{{datetime}}', uBlockDashboard.dateNowToSensibleString()) @@ -164,7 +172,7 @@ const exportUserFiltersToFile = function() { const applyChanges = async function() { const details = await vAPI.messaging.send('dashboard', { what: 'writeUserFilters', - content: cmEditor.getValue(), + content: getEditorText(), }); if ( details instanceof Object === false || details.error ) { return; } @@ -176,23 +184,19 @@ const applyChanges = async function() { }; const revertChanges = function() { - let content = cachedUserFilters; - if ( content.length !== 0 ) { - content += '\n'; - } - cmEditor.setValue(content); + setEditorText(cachedUserFilters); }; /******************************************************************************/ const getCloudData = function() { - return cmEditor.getValue(); + return getEditorText(); }; const setCloudData = function(data, append) { if ( typeof data !== 'string' ) { return; } if ( append ) { - data = uBlockDashboard.mergeNewLines(cmEditor.getValue(), data); + data = uBlockDashboard.mergeNewLines(getEditorText(), data); } cmEditor.setValue(data); }; @@ -203,7 +207,7 @@ self.cloud.onPull = setCloudData; /******************************************************************************/ self.hasUnsavedData = function() { - return cmEditor.getValue().trim() !== cachedUserFilters; + return getEditorText().trim() !== cachedUserFilters; }; /******************************************************************************/ diff --git a/src/js/3p-filters.js b/src/js/3p-filters.js index 2a024cfc273ea..291306177e3d0 100644 --- a/src/js/3p-filters.js +++ b/src/js/3p-filters.js @@ -30,7 +30,7 @@ /******************************************************************************/ const lastUpdateTemplateString = vAPI.i18n('3pLastUpdate'); -const reValidExternalList = /[a-z-]+:\/\/\S*\/\S+/; +const reValidExternalList = /^[a-z-]+:\/\/(?:\S+\/\S*|\/\S+)/m; let listDetails = {}; let filteringSettingsHash = ''; diff --git a/src/js/about.js b/src/js/about.js index 2aab628a39dfb..6ceb42255a07f 100644 --- a/src/js/about.js +++ b/src/js/about.js @@ -34,4 +34,23 @@ button.removeAttribute('disabled'); }); }); + + uDom('#aboutNameVer').text(appData.name + ' v' + appData.version); + + if ( appData.canBenchmark !== true ) { return; } + + document.getElementById('dev').classList.add('enabled'); + + document.getElementById('sfneBenchmark').addEventListener('click', ev => { + const button = ev.target; + button.setAttribute('disabled', ''); + vAPI.messaging.send('dashboard', { + what: 'sfneBenchmark', + }).then(result => { + document.getElementById('sfneBenchmarkResult').prepend( + document.createTextNode(result.trim() + '\n') + ); + button.removeAttribute('disabled'); + }); + }); })(); diff --git a/src/js/asset-viewer.js b/src/js/asset-viewer.js index 1e03771c76659..ecdef01c24c29 100644 --- a/src/js/asset-viewer.js +++ b/src/js/asset-viewer.js @@ -53,7 +53,9 @@ matchBrackets: true, maxScanLines: 1, readOnly: true, - styleActiveLine: true, + styleActiveLine: { + nonEmpty: true, + }, }); uBlockDashboard.patchCodeMirrorEditor(cmEditor); diff --git a/src/js/background.js b/src/js/background.js index da5b1cd1f8f1a..e616a0335148d 100644 --- a/src/js/background.js +++ b/src/js/background.js @@ -47,7 +47,7 @@ const µBlock = (( ) => { // jshint ignore:line cacheStorageAPI: 'unset', cacheStorageCompression: true, cacheControlForFirefox1376932: 'no-cache, no-store, must-revalidate', - cloudStorageCompression: false, + cloudStorageCompression: true, cnameIgnoreList: 'unset', cnameIgnore1stParty: true, cnameIgnoreExceptions: true, @@ -77,6 +77,7 @@ const µBlock = (( ) => { // jshint ignore:line uiPopupConfig: 'undocumented', uiFlavor: 'unset', uiStyles: 'unset', + uiTheme: 'unset', updateAssetBypassBrowserCache: false, userResourcesLocation: 'unset', }; @@ -161,8 +162,8 @@ const µBlock = (( ) => { // jshint ignore:line // Read-only systemSettings: { - compiledMagic: 29, // Increase when compiled format changes - selfieMagic: 29, // Increase when selfie format changes + compiledMagic: 34, // Increase when compiled format changes + selfieMagic: 34, // Increase when selfie format changes }, // https://github.com/uBlockOrigin/uBlock-issues/issues/759#issuecomment-546654501 diff --git a/src/js/click2load.js b/src/js/click2load.js new file mode 100644 index 0000000000000..c0e0b4cc355b1 --- /dev/null +++ b/src/js/click2load.js @@ -0,0 +1,64 @@ +/******************************************************************************* + + 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'; + +/******************************************************************************/ +/******************************************************************************/ + +(( ) => { + +/******************************************************************************/ + +if ( typeof vAPI !== 'object' ) { return; } + +const url = new URL(self.location.href); +const frameURL = url.searchParams.get('url'); +const frameURLElem = document.getElementById('frameURL'); + +frameURLElem.children[0].textContent = frameURL; +frameURLElem.children[1].href = frameURL; + +const onWindowResize = function() { + document.body.style.width = `${self.innerWidth}px`; + document.body.style.height = `${self.innerHeight}px`; +}; + +onWindowResize(); + +self.addEventListener('resize', onWindowResize); + +document.body.addEventListener('click', ev => { + if ( ev.isTrusted === false ) { return; } + if ( ev.target.closest('#frameURL') !== null ) { return; } + vAPI.messaging.send('default', { + what: 'clickToLoad', + frameURL, + }).then(ok => { + if ( ok ) { + self.location.replace(frameURL); + } + }); +}); + +/******************************************************************************/ + +})(); diff --git a/src/js/codemirror/ubo-static-filtering.js b/src/js/codemirror/ubo-static-filtering.js index 24d257d60eb74..b4a74239caffd 100644 --- a/src/js/codemirror/ubo-static-filtering.js +++ b/src/js/codemirror/ubo-static-filtering.js @@ -44,22 +44,33 @@ CodeMirror.defineMode('ubo-static-filtering', function() { if ( StaticFilteringParser instanceof Object === false ) { return; } const parser = new StaticFilteringParser({ interactive: true }); + const reURL = /\bhttps?:\/\/\S+/; const rePreparseDirectives = /^!#(?:if|endif|include )\b/; const rePreparseIfDirective = /^(!#if ?)(.*)$/; let parserSlot = 0; let netOptionValueMode = false; const colorCommentSpan = function(stream) { - if ( rePreparseDirectives.test(stream.string) === false ) { + const { string, pos } = stream; + if ( rePreparseDirectives.test(string) === false ) { + const match = reURL.exec(string.slice(pos)); + if ( match !== null ) { + if ( match.index === 0 ) { + stream.pos += match[0].length; + return 'comment link'; + } + stream.pos += match.index; + return 'comment'; + } stream.skipToEnd(); return 'comment'; } - const match = rePreparseIfDirective.exec(stream.string); + const match = rePreparseIfDirective.exec(string); if ( match === null ) { stream.skipToEnd(); return 'variable strong'; } - if ( stream.pos < match[1].length ) { + if ( pos < match[1].length ) { stream.pos += match[1].length; return 'variable strong'; } @@ -95,19 +106,29 @@ CodeMirror.defineMode('ubo-static-filtering', function() { }; const colorExtScriptletPatternSpan = function(stream) { + const { pos, string } = stream; const { i, len } = parser.patternSpan; - if ( stream.pos === parser.slices[i+1] ) { - stream.pos += 4; + const patternBeg = parser.slices[i+1]; + if ( pos === patternBeg ) { + stream.pos = pos + 4; return 'def'; } if ( len > 3 ) { + if ( pos === patternBeg + 4 ) { + const match = /^[^,)]+/.exec(string.slice(pos)); + const token = match && match[0].trim(); + if ( token && scriptletNames.has(token) === false ) { + stream.pos = pos + match[0].length; + return 'warning'; + } + } const r = parser.slices[i+len+1] - 1; - if ( stream.pos < r ) { + if ( pos < r ) { stream.pos = r; return 'variable'; } - if ( stream.pos === r ) { - stream.pos += 1; + if ( pos === r ) { + stream.pos = pos + 1; return 'def'; } } @@ -156,6 +177,56 @@ CodeMirror.defineMode('ubo-static-filtering', function() { return null; }; + const colorNetOptionValueSpan = function(stream, bits) { + const { pos, string } = stream; + let style; + // Warn about unknown redirect tokens. + if ( + string.charCodeAt(pos - 1) === 0x3D /* '=' */ && + /[$,]redirect(-rule)?=$/.test(string.slice(0, pos)) + ) { + style = 'value'; + let end = parser.skipUntil( + parserSlot, + parser.commentSpan.i, + parser.BITComma + ); + const token = parser.strFromSlices(parserSlot, end - 3); + if ( redirectNames.has(token) === false ) { + style += ' warning'; + } + stream.pos += token.length; + parserSlot = end; + return style; + } + if ( (bits & parser.BITTilde) !== 0 ) { + style = 'keyword strong'; + } else if ( (bits & parser.BITPipe) !== 0 ) { + style = 'def'; + } + stream.pos += parser.slices[parserSlot+2]; + parserSlot += 3; + return style || 'value'; + }; + + const colorNetOptionSpan = function(stream) { + const bits = parser.slices[parserSlot]; + let style; + if ( (bits & parser.BITComma) !== 0 ) { + style = 'def strong'; + netOptionValueMode = false; + } else if ( netOptionValueMode ) { + return colorNetOptionValueSpan(stream, bits); + } else if ( (bits & parser.BITTilde) !== 0 ) { + style = 'keyword strong'; + } else if ( (bits & parser.BITEqual) !== 0 ) { + netOptionValueMode = true; + } + stream.pos += parser.slices[parserSlot+2]; + parserSlot += 3; + return style || 'def'; + }; + const colorNetSpan = function(stream) { if ( parserSlot < parser.exceptionSpan.i ) { stream.pos += parser.slices[parserSlot+2]; @@ -215,23 +286,7 @@ CodeMirror.defineMode('ubo-static-filtering', function() { parserSlot >= parser.optionsSpan.i && parserSlot < parser.commentSpan.i ) { - const bits = parser.slices[parserSlot]; - let style; - if ( (bits & parser.BITComma) !== 0 ) { - style = 'def strong'; - netOptionValueMode = false; - } else if ( (bits & parser.BITTilde) !== 0 ) { - style = 'keyword strong'; - } else if ( (bits & parser.BITPipe) !== 0 ) { - style = 'def'; - } else if ( netOptionValueMode ) { - style = 'value'; - } else if ( (bits & parser.BITEqual) !== 0 ) { - netOptionValueMode = true; - } - stream.pos += parser.slices[parserSlot+2]; - parserSlot += 3; - return style || 'def'; + return colorNetOptionSpan(stream); } if ( parserSlot >= parser.commentSpan.i && @@ -263,10 +318,12 @@ CodeMirror.defineMode('ubo-static-filtering', function() { return 'comment'; } if ( parser.category === parser.CATStaticExtFilter ) { - return colorExtSpan(stream); + const style = colorExtSpan(stream); + return style ? `ext ${style}` : 'ext'; } if ( parser.category === parser.CATStaticNetFilter ) { - return colorNetSpan(stream); + const style = colorNetSpan(stream); + return style ? `net ${style}` : 'net'; } stream.skipToEnd(); return null; @@ -275,13 +332,14 @@ CodeMirror.defineMode('ubo-static-filtering', function() { return { lineComment: '!', token: function(stream) { + let style = ''; if ( stream.sol() ) { parser.analyze(stream.string); parser.analyzeExtra(); parserSlot = 0; netOptionValueMode = false; } - let style = colorSpan(stream) || ''; + style += colorSpan(stream) || ''; if ( (parser.flavorBits & parser.BITFlavorError) !== 0 ) { style += ' line-background-error'; } @@ -306,6 +364,9 @@ CodeMirror.defineMode('ubo-static-filtering', function() { preparseDirectiveHints.push(...details.preparseDirectiveHints); initHints(); }, + get parser() { + return parser; + }, }; }); @@ -362,7 +423,7 @@ const initHints = function() { if ( assignPos !== -1 ) { seedRight = seedRight.slice(0, assignPos); } const isException = parser.isException(); const hints = []; - for ( let [ text, bits ] of parser.netOptionTokens ) { + for ( let [ text, bits ] of parser.netOptionTokenDescriptors ) { if ( isNegated && (bits & parser.OPTCanNegate) === 0 ) { continue; } if ( isException ) { if ( (bits & parser.OPTBlockOnly) !== 0 ) { continue; } @@ -483,7 +544,6 @@ const initHints = function() { /******************************************************************************/ CodeMirror.registerHelper('fold', 'ubo-static-filtering', (( ) => { - const foldIfEndif = function(startLineNo, startLine, cm) { const lastLineNo = cm.lastLine(); let endLineNo = startLineNo; @@ -539,6 +599,99 @@ CodeMirror.registerHelper('fold', 'ubo-static-filtering', (( ) => { /******************************************************************************/ +// Enhanced word selection + +{ + const Pass = CodeMirror.Pass; + + const selectWordAt = function(cm, pos) { + const { line, ch } = pos; + + // Leave current selection alone + if ( cm.somethingSelected() ) { + const from = cm.getCursor('from'); + const to = cm.getCursor('to'); + if ( + (line > from.line || line === from.line && ch > from.ch) && + (line < to.line || line === to.line && ch < to.ch) + ) { + return Pass; + } + } + + const s = cm.getLine(line); + const token = cm.getTokenTypeAt(pos); + let beg, end; + + // Select URL in comments + if ( /\bcomment\b/.test(token) && /\blink\b/.test(token) ) { + const l = /\S+$/.exec(s.slice(0, ch)); + if ( l && /^https?:\/\//.test(s.slice(l.index)) ) { + const r = /^\S+/.exec(s.slice(ch)); + if ( r ) { + beg = l.index; + end = ch + r[0].length; + } + } + } + + // Better word selection for cosmetic filters + else if ( /\bext\b/.test(token) ) { + if ( /\bvalue\b/.test(token) ) { + const l = /[^,.]*$/i.exec(s.slice(0, ch)); + const r = /^[^#,]*/i.exec(s.slice(ch)); + if ( l && r ) { + beg = l.index; + end = ch + r[0].length; + } + } else if ( /\bvariable\b/.test(token) ) { + const l = /[#.]?[a-z0-9_-]+$/i.exec(s.slice(0, ch)); + const r = /^[a-z0-9_-]+/i.exec(s.slice(ch)); + if ( l && r ) { + beg = l.index; + end = ch + r[0].length; + if ( /\bdef\b/.test(cm.getTokenTypeAt({ line, ch: beg + 1 })) ) { + beg += 1; + } + } + } + } + + // Better word selection for network filters + else if ( /\bnet\b/.test(token) ) { + if ( /\bvalue\b/.test(token) ) { + const l = /[^ ,.=|]*$/i.exec(s.slice(0, ch)); + const r = /^[^ #,|]*/i.exec(s.slice(ch)); + if ( l && r ) { + beg = l.index; + end = ch + r[0].length; + } + } else if ( /\bdef\b/.test(token) ) { + const l = /[a-z0-9-]+$/i.exec(s.slice(0, ch)); + const r = /^[^,]*=[^,]+/i.exec(s.slice(ch)); + if ( l && r ) { + beg = l.index; + end = ch + r[0].length; + } + } + } + + if ( beg === undefined ) { return Pass; } + cm.setSelection( + { line, ch: beg }, + { line, ch: end } + ); + }; + + CodeMirror.defineInitHook(cm => { + cm.addKeyMap({ + 'LeftDoubleClick': selectWordAt, + }); + }); +} + +/******************************************************************************/ + // <<<<< end of local scope } diff --git a/src/js/contentscript.js b/src/js/contentscript.js index be51b69555c92..d29e555e1c74a 100644 --- a/src/js/contentscript.js +++ b/src/js/contentscript.js @@ -437,7 +437,7 @@ vAPI.SafeAnimationFrame = class { const cleanup = function() { if ( domLayoutObserver !== undefined ) { domLayoutObserver.disconnect(); - domLayoutObserver = null; + domLayoutObserver = undefined; } if ( safeObserverHandlerTimer !== undefined ) { safeObserverHandlerTimer.clear(); @@ -855,7 +855,7 @@ vAPI.injectScriptlet = function(doc, text) { this.domFilterer.addCSSRule( `[${this.masterToken}][${styleToken}]`, style, - { silent: true } + { silent: true, mustInject: true } ); return styleToken; } @@ -912,7 +912,6 @@ vAPI.injectScriptlet = function(doc, text) { this.disabled = false; this.listeners = []; this.filterset = new Set(); - this.addedCSSRules = new Set(); this.exceptedCSSRules = []; this.exceptions = []; this.proceduralFilterer = null; @@ -933,22 +932,11 @@ vAPI.injectScriptlet = function(doc, text) { addCSSRule(selectors, declarations, details = {}) { if ( selectors === undefined ) { return; } const selectorsStr = Array.isArray(selectors) - ? selectors.join(',\n') - : selectors; + ? selectors.join(',\n') + : selectors; if ( selectorsStr.length === 0 ) { return; } - const entry = { - selectors: selectorsStr, - declarations, - lazy: details.lazy === true, - injected: details.injected === true - }; - this.addedCSSRules.add(entry); - this.filterset.add(entry); - if ( - this.disabled === false && - entry.lazy !== true && - entry.injected !== true - ) { + this.filterset.add({ selectors: selectorsStr, declarations }); + if ( details.mustInject && this.disabled === false ) { vAPI.userStylesheet.add(`${selectorsStr}\n{${declarations}}`); } this.commit(); @@ -1016,20 +1004,7 @@ vAPI.injectScriptlet = function(doc, text) { commitNow() { this.commitTimer.clear(); if ( vAPI instanceof Object === false ) { return; } - const userStylesheet = vAPI.userStylesheet; - for ( const entry of this.addedCSSRules ) { - if ( - this.disabled === false && - entry.lazy && - entry.injected === false - ) { - userStylesheet.add( - `${entry.selectors}\n{${entry.declarations}}` - ); - } - } - this.addedCSSRules.clear(); - userStylesheet.apply(); + vAPI.userStylesheet.apply(); if ( this.proceduralFilterer instanceof Object ) { this.proceduralFilterer.commitNow(); } @@ -1063,11 +1038,11 @@ vAPI.injectScriptlet = function(doc, text) { o.action[0] === ':style' && o.tasks === undefined ) { - this.addCSSRule(o.selector, o.action[1]); + this.addCSSRule(o.selector, o.action[1], { mustInject: true }); continue; } if ( o.pseudo !== undefined ) { - this.addCSSRule(o.selector, vAPI.hideStyle); + this.addCSSRule(o.selector, vAPI.hideStyle, { mustInject: true }); continue; } procedurals.push(o); @@ -1128,21 +1103,26 @@ vAPI.injectScriptlet = function(doc, text) { const messaging = vAPI.messaging; const toCollapse = new Map(); const src1stProps = { + audio: 'currentSrc', embed: 'src', iframe: 'src', - img: 'src', - object: 'data' + img: 'currentSrc', + object: 'data', + video: 'currentSrc', }; const src2ndProps = { - img: 'srcset' + audio: 'src', + img: 'src', + video: 'src', }; const tagToTypeMap = { + audio: 'media', embed: 'object', iframe: 'sub_frame', img: 'image', - object: 'object' + object: 'object', + video: 'media', }; - let resquestIdGenerator = 1, processTimer, cachedBlockedSet, @@ -1158,6 +1138,21 @@ vAPI.injectScriptlet = function(doc, text) { cachedBlockedSetTimer = undefined; }; + // https://github.com/chrisaljoudi/uBlock/issues/399 + // https://github.com/gorhill/uBlock/issues/2848 + // Use a user stylesheet to collapse placeholders. + const getCollapseToken = ( ) => { + if ( collapseToken === undefined ) { + collapseToken = vAPI.randomToken(); + vAPI.userStylesheet.add( + `[${collapseToken}]\n{display:none!important;}`, + true + ); + } + return collapseToken; + }; + let collapseToken; + // https://github.com/chrisaljoudi/uBlock/issues/174 // Do not remove fragment from src URL const onProcessed = function(response) { @@ -1169,6 +1164,7 @@ vAPI.injectScriptlet = function(doc, text) { const targets = toCollapse.get(response.id); if ( targets === undefined ) { return; } + toCollapse.delete(response.id); if ( cachedBlockedSetHash !== response.hash ) { cachedBlockedSet = new Set(response.blockedResources); @@ -1181,8 +1177,8 @@ vAPI.injectScriptlet = function(doc, text) { if ( cachedBlockedSet === undefined || cachedBlockedSet.size === 0 ) { return; } + const selectors = []; - const iframeLoadEventPatch = vAPI.iframeLoadEventPatch; let netSelectorCacheCountMax = response.netSelectorCacheCountMax; for ( const target of targets ) { @@ -1199,32 +1195,24 @@ vAPI.injectScriptlet = function(doc, text) { if ( cachedBlockedSet.has(tagToTypeMap[tag] + ' ' + src) === false ) { continue; } - // https://github.com/chrisaljoudi/uBlock/issues/399 - // Never remove elements from the DOM, just hide them - target.style.setProperty('display', 'none', 'important'); - target.hidden = true; + target.setAttribute(getCollapseToken(), ''); // https://github.com/chrisaljoudi/uBlock/issues/1048 - // Use attribute to construct CSS rule - if ( netSelectorCacheCount <= netSelectorCacheCountMax ) { - const value = target.getAttribute(prop); - if ( value ) { - selectors.push(`${tag}[${prop}="${CSS.escape(value)}"]`); - netSelectorCacheCount += 1; - } - } - if ( iframeLoadEventPatch !== undefined ) { - iframeLoadEventPatch(target); + // Use attribute to construct CSS rule + if ( netSelectorCacheCount > netSelectorCacheCountMax ) { continue; } + const value = target.getAttribute(prop); + if ( value ) { + selectors.push(`${tag}[${prop}="${CSS.escape(value)}"]`); + netSelectorCacheCount += 1; } } - if ( selectors.length !== 0 ) { - messaging.send('contentscript', { - what: 'cosmeticFiltersInjected', - type: 'net', - hostname: window.location.hostname, - selectors, - }); - } + if ( selectors.length === 0 ) { return; } + messaging.send('contentscript', { + what: 'cosmeticFiltersInjected', + type: 'net', + hostname: window.location.hostname, + selectors, + }); }; const send = function() { @@ -1545,7 +1533,6 @@ vAPI.injectScriptlet = function(doc, text) { domFilterer.addCSSRule( selectors, vAPI.hideStyle, - { injected: true } ); mustCommit = true; } @@ -1737,11 +1724,7 @@ vAPI.injectScriptlet = function(doc, text) { vAPI.domSurveyor = null; } domFilterer.exceptions = cfeDetails.exceptionFilters; - domFilterer.addCSSRule( - cfeDetails.injectedHideFilters, - vAPI.hideStyle, - { injected: true } - ); + domFilterer.addCSSRule(cfeDetails.injectedHideFilters, vAPI.hideStyle); domFilterer.addProceduralSelectors(cfeDetails.proceduralFilters); domFilterer.exceptCSSRules(cfeDetails.exceptedFilters); } diff --git a/src/js/document-blocked.js b/src/js/document-blocked.js index 0bda0f99d6c7e..e89b030082b2e 100644 --- a/src/js/document-blocked.js +++ b/src/js/document-blocked.js @@ -60,19 +60,17 @@ let details = {}; const parent = uDom.nodeFromSelector('#whyex > span:nth-of-type(2)'); for ( const list of lists ) { - const elem = document.querySelector('#templates .filterList') - .cloneNode(true); - const source = elem.querySelector('.filterListSource'); - source.href += encodeURIComponent(list.assetKey); - source.textContent = list.title; - if ( - typeof list.supportURL === 'string' && - list.supportURL !== '' - ) { - elem.querySelector('.filterListSupport') - .setAttribute('href', list.supportURL); + const listElem = document.querySelector('#templates .filterList') + .cloneNode(true); + const sourceElem = listElem.querySelector('.filterListSource'); + sourceElem.href += encodeURIComponent(list.assetKey); + sourceElem.textContent = list.title; + if ( typeof list.supportURL === 'string' && list.supportURL !== '' ) { + const supportElem = listElem.querySelector('.filterListSupport'); + supportElem.setAttribute('href', list.supportURL); + supportElem.classList.remove('hidden'); } - parent.appendChild(elem); + parent.appendChild(listElem); } uDom.nodeFromId('whyex').style.removeProperty('display'); })(); diff --git a/src/js/dyna-rules.js b/src/js/dyna-rules.js index 7d1df962470b5..581d48fc669d3 100644 --- a/src/js/dyna-rules.js +++ b/src/js/dyna-rules.js @@ -39,7 +39,7 @@ const mergeView = new CodeMirror.MergeView( lineWrapping: false, origLeft: '', revertButtons: true, - value: '' + value: '', } ); mergeView.editor().setOption('styleActiveLine', true); diff --git a/src/js/epicker-ui.js b/src/js/epicker-ui.js index abb9d86edfe50..84a9a963a2c90 100644 --- a/src/js/epicker-ui.js +++ b/src/js/epicker-ui.js @@ -19,6 +19,8 @@ Home: https://github.com/gorhill/uBlock */ +/* global CodeMirror */ + 'use strict'; /******************************************************************************/ @@ -36,7 +38,6 @@ const $storAll = selector => document.querySelectorAll(selector); const pickerRoot = document.documentElement; const dialog = $stor('aside'); -const taCandidate = $stor('textarea'); let staticFilteringParser; const svgRoot = $stor('svg'); @@ -53,27 +54,65 @@ const epickerId = (( ) => { })(); if ( epickerId === null ) { return; } +const docURL = new URL(vAPI.getURL('')); + let epickerConnectionId; -let filterHostname = ''; -let filterOrigin = ''; let resultsetOpt; let netFilterCandidates = []; let cosmeticFilterCandidates = []; let computedCandidateSlot = 0; let computedCandidate = ''; +const computedSpecificityCandidates = new Map(); let needBody = false; /******************************************************************************/ +const cmEditor = new CodeMirror(document.querySelector('.codeMirrorContainer'), { + autoCloseBrackets: true, + autofocus: true, + extraKeys: { + 'Ctrl-Space': 'autocomplete', + }, + lineWrapping: true, + matchBrackets: true, + maxScanLines: 1, +}); + +vAPI.messaging.send('dashboard', { + what: 'getAutoCompleteDetails' +}).then(response => { + if ( response instanceof Object === false ) { return; } + const mode = cmEditor.getMode(); + if ( mode.setHints instanceof Function ) { + mode.setHints(response); + } +}); + +/******************************************************************************/ + +const rawFilterFromTextarea = function() { + const text = cmEditor.getValue(); + const pos = text.indexOf('\n'); + return pos === -1 ? text : text.slice(0, pos); +}; + +/******************************************************************************/ + const filterFromTextarea = function() { - const s = taCandidate.value.trim(); - if ( s === '' ) { return ''; } - const pos = s.indexOf('\n'); - const filter = pos === -1 ? s.trim() : s.slice(0, pos).trim(); - staticFilteringParser.analyze(filter); - staticFilteringParser.analyzeExtra(); - return staticFilteringParser.shouldDiscard() ? '!' : filter; + const filter = rawFilterFromTextarea(); + if ( filter === '' ) { return ''; } + const sfp = staticFilteringParser; + sfp.analyze(filter); + sfp.analyzeExtra(); + if ( + sfp.category !== sfp.CATStaticExtFilter && + sfp.category !== sfp.CATStaticNetFilter || + sfp.shouldDiscard() + ) { + return '!'; + } + return filter; }; /******************************************************************************/ @@ -102,9 +141,11 @@ const renderRange = function(id, value, invert = false) { const userFilterFromCandidate = function(filter) { if ( filter === '' || filter === '!' ) { return; } + const hn = vAPI.hostnameFromURI(docURL.href); + // Cosmetic filter? if ( filter.startsWith('##') ) { - return filterHostname + filter; + return hn + filter; } // Assume net filter @@ -112,7 +153,7 @@ const userFilterFromCandidate = function(filter) { // If no domain included in filter, we need domain option if ( filter.startsWith('||') === false ) { - opts.push(`domain=${filterHostname}`); + opts.push(`domain=${hn}`); } if ( resultsetOpt !== undefined ) { @@ -154,7 +195,23 @@ const candidateFromFilterChoice = function(filterChoice) { $stor(`#cosmeticFilters li:nth-of-type(${slot+1})`) .classList.add('active'); - const specificity = [ + return cosmeticCandidatesFromFilterChoice(filterChoice); +}; + +/******************************************************************************/ + +const cosmeticCandidatesFromFilterChoice = function(filterChoice) { + let { slot, filters } = filterChoice; + + renderRange('resultsetDepth', slot, true); + renderRange('resultsetSpecificity'); + + if ( computedSpecificityCandidates.has(slot) ) { + onCandidatesOptimized({ slot }); + return; + } + + const specificities = [ 0b0000, // remove hierarchy; remove id, nth-of-type, attribute values 0b0010, // remove hierarchy; remove id, nth-of-type 0b0011, // remove hierarchy @@ -163,90 +220,103 @@ const candidateFromFilterChoice = function(filterChoice) { 0b1100, // remove id, nth-of-type, attribute values 0b1110, // remove id, nth-of-type 0b1111, // keep all = most specific - ][ parseInt($stor('#resultsetSpecificity input').value, 10) ]; - - // Return path: the target element, then all siblings prepended - const paths = []; - for ( let i = slot; i < filters.length; i++ ) { - filter = filters[i].slice(2); - // Remove id, nth-of-type - // https://github.com/uBlockOrigin/uBlock-issues/issues/162 - // Mind escaped periods: they do not denote a class identifier. - if ( (specificity & 0b0001) === 0 ) { - filter = filter.replace(/:nth-of-type\(\d+\)/, ''); - if ( - filter.charAt(0) === '#' && ( - (specificity & 0b1000) === 0 || i === slot - ) - ) { - const pos = filter.search(/[^\\]\./); - if ( pos !== -1 ) { - filter = filter.slice(pos + 1); + ]; + + const candidates = []; + + let filter = filters[slot]; + + for ( const specificity of specificities ) { + // Return path: the target element, then all siblings prepended + const paths = []; + for ( let i = slot; i < filters.length; i++ ) { + filter = filters[i].slice(2); + // Remove id, nth-of-type + // https://github.com/uBlockOrigin/uBlock-issues/issues/162 + // Mind escaped periods: they do not denote a class identifier. + if ( (specificity & 0b0001) === 0 ) { + filter = filter.replace(/:nth-of-type\(\d+\)/, ''); + if ( + filter.charAt(0) === '#' && ( + (specificity & 0b1000) === 0 || i === slot + ) + ) { + const pos = filter.search(/[^\\]\./); + if ( pos !== -1 ) { + filter = filter.slice(pos + 1); + } } } - } - // Remove attribute values. - if ( (specificity & 0b0010) === 0 ) { - const match = /^\[([^^=]+)\^?=.+\]$/.exec(filter); - if ( match !== null ) { - filter = `[${match[1]}]`; + // Remove attribute values. + if ( (specificity & 0b0010) === 0 ) { + const match = /^\[([^^=]+)\^?=.+\]$/.exec(filter); + if ( match !== null ) { + filter = `[${match[1]}]`; + } + } + // Remove all classes when an id exists. + // https://github.com/uBlockOrigin/uBlock-issues/issues/162 + // Mind escaped periods: they do not denote a class identifier. + if ( filter.charAt(0) === '#' ) { + filter = filter.replace(/([^\\])\..+$/, '$1'); + } + if ( paths.length !== 0 ) { + filter += ' > '; + } + paths.unshift(filter); + // Stop at any element with an id: these are unique in a web page + if ( (specificity & 0b1000) === 0 || filter.startsWith('#') ) { + break; } } - // Remove all classes when an id exists. - // https://github.com/uBlockOrigin/uBlock-issues/issues/162 - // Mind escaped periods: they do not denote a class identifier. - if ( filter.charAt(0) === '#' ) { - filter = filter.replace(/([^\\])\..+$/, '$1'); - } - if ( paths.length !== 0 ) { - filter += ' > '; - } - paths.unshift(filter); - // Stop at any element with an id: these are unique in a web page - if ( (specificity & 0b1000) === 0 || filter.startsWith('#') ) { break; } - } - // Trim hierarchy: remove generic elements from path - if ( (specificity & 0b1100) === 0b1000 ) { - let i = 0; - while ( i < paths.length - 1 ) { - if ( /^[a-z0-9]+ > $/.test(paths[i+1]) ) { - if ( paths[i].endsWith(' > ') ) { - paths[i] = paths[i].slice(0, -2); + // Trim hierarchy: remove generic elements from path + if ( (specificity & 0b1100) === 0b1000 ) { + let i = 0; + while ( i < paths.length - 1 ) { + if ( /^[a-z0-9]+ > $/.test(paths[i+1]) ) { + if ( paths[i].endsWith(' > ') ) { + paths[i] = paths[i].slice(0, -2); + } + paths.splice(i + 1, 1); + } else { + i += 1; } - paths.splice(i + 1, 1); - } else { - i += 1; } } - } - - if ( - needBody && - paths.length !== 0 && - paths[0].startsWith('#') === false && - (specificity & 0b1100) !== 0 - ) { - paths.unshift('body > '); - } - if ( paths.length === 0 ) { return ''; } + if ( + needBody && + paths.length !== 0 && + paths[0].startsWith('#') === false && + paths[0].startsWith('body ') === false && + (specificity & 0b1100) !== 0 + ) { + paths.unshift('body > '); + } - renderRange('resultsetDepth', slot, true); - renderRange('resultsetSpecificity'); + candidates.push(paths); + } vAPI.MessagingConnection.sendTo(epickerConnectionId, { - what: 'optimizeCandidate', - paths, + what: 'optimizeCandidates', + candidates, + slot, }); }; /******************************************************************************/ -const onCandidateOptimized = function(details) { +const onCandidatesOptimized = function(details) { $id('resultsetModifiers').classList.remove('hide'); - computedCandidate = details.filter; - taCandidate.value = computedCandidate; + const i = parseInt($stor('#resultsetSpecificity input').value, 10); + if ( Array.isArray(details.candidates) ) { + computedSpecificityCandidates.set(details.slot, details.candidates); + } + const candidates = computedSpecificityCandidates.get(details.slot); + computedCandidate = candidates[i]; + cmEditor.setValue(computedCandidate); + cmEditor.clearHistory(); onCandidateChanged(); }; @@ -383,9 +453,9 @@ const onCandidateChanged = function() { $id('resultsetCount').textContent = 'E'; $id('create').setAttribute('disabled', ''); } + const text = rawFilterFromTextarea(); $id('resultsetModifiers').classList.toggle( - 'hide', - taCandidate.value === '' || taCandidate.value !== computedCandidate + 'hide', text === '' || text !== computedCandidate ); vAPI.MessagingConnection.sendTo(epickerConnectionId, { what: 'dialogSetFilter', @@ -416,8 +486,7 @@ const onCreateClicked = function() { what: 'createUserFilter', autoComment: true, filters: filter, - origin: filterOrigin, - pageDomain: filterHostname, + docURL: docURL.href, killCache: /^#[$?]?#/.test(candidate) === false, }); } @@ -453,20 +522,23 @@ const onDepthChanged = function() { slot: max - value, }); if ( text === undefined ) { return; } - taCandidate.value = text; + cmEditor.setValue(text); + cmEditor.clearHistory(); onCandidateChanged(); }; /******************************************************************************/ const onSpecificityChanged = function() { - if ( taCandidate.value !== computedCandidate ) { return; } - const text = candidateFromFilterChoice({ - filters: cosmeticFilterCandidates, - slot: computedCandidateSlot, - }); - if ( text === undefined ) { return; } - taCandidate.value = text; + renderRange('resultsetSpecificity'); + if ( rawFilterFromTextarea() !== computedCandidate ) { return; } + const depthInput = $stor('#resultsetDepth input'); + const slot = parseInt(depthInput.max, 10) - parseInt(depthInput.value, 10); + const i = parseInt($stor('#resultsetSpecificity input').value, 10); + const candidates = computedSpecificityCandidates.get(slot); + computedCandidate = candidates[i]; + cmEditor.setValue(computedCandidate); + cmEditor.clearHistory(); onCandidateChanged(); }; @@ -487,7 +559,8 @@ const onCandidateClicked = function(ev) { } const text = candidateFromFilterChoice(choice); if ( text === undefined ) { return; } - taCandidate.value = text; + cmEditor.setValue(text); + cmEditor.clearHistory(); onCandidateChanged(); }; @@ -555,7 +628,7 @@ const onStartMoving = (( ) => { }; return function(ev) { - const target = dialog.querySelector('#toolbar'); + const target = dialog.querySelector('#move'); if ( ev.target !== target ) { return; } if ( dialog.classList.contains('moving') ) { return; } isTouch = ev.type.startsWith('touch'); @@ -672,16 +745,11 @@ const showDialog = function(details) { } cosmeticFilterCandidates = cosmeticFilters; - // https://github.com/gorhill/uBlock/issues/738 - // Trim dots. - filterHostname = details.hostname; - if ( filterHostname.slice(-1) === '.' ) { - filterHostname = filterHostname.slice(0, -1); - } - filterOrigin = details.origin; + docURL.href = details.url; populateCandidates(netFilters, '#netFilters'); populateCandidates(cosmeticFilters, '#cosmeticFilters'); + computedSpecificityCandidates.clear(); const depthInput = $stor('#resultsetDepth input'); depthInput.max = cosmeticFilters.length - 1; @@ -700,7 +768,7 @@ const showDialog = function(details) { // This is an issue which surfaced when the element picker code was // revisited to isolate the picker dialog DOM from the page DOM. if ( typeof filter !== 'object' || filter === null ) { - taCandidate.value = ''; + cmEditor.setValue(''); return; } @@ -711,7 +779,7 @@ const showDialog = function(details) { const text = candidateFromFilterChoice(filterChoice); if ( text === undefined ) { return; } - taCandidate.value = text; + cmEditor.setValue(text); onCandidateChanged(); }; @@ -746,13 +814,14 @@ const startPicker = function() { if ( pickerRoot.classList.contains('zap') ) { return; } - taCandidate.addEventListener('input', onCandidateChanged); + cmEditor.on('changes', onCandidateChanged); + $id('preview').addEventListener('click', onPreviewClicked); $id('create').addEventListener('click', onCreateClicked); $id('pick').addEventListener('click', onPickClicked); $id('quit').addEventListener('click', onQuitClicked); - $id('toolbar').addEventListener('mousedown', onStartMoving); - $id('toolbar').addEventListener('touchstart', onStartMoving); + $id('move').addEventListener('mousedown', onStartMoving); + $id('move').addEventListener('touchstart', onStartMoving); $id('candidateFilters').addEventListener('click', onCandidateClicked); $stor('#resultsetDepth input').addEventListener('input', onDepthChanged); $stor('#resultsetSpecificity input').addEventListener('input', onSpecificityChanged); @@ -770,8 +839,8 @@ const quitPicker = function() { const onPickerMessage = function(msg) { switch ( msg.what ) { - case 'candidateOptimized': - onCandidateOptimized(msg); + case 'candidatesOptimized': + onCandidatesOptimized(msg); break; case 'showDialog': showDialog(msg); diff --git a/src/js/filtering-context.js b/src/js/filtering-context.js index 9623723059ea8..af68ca19e5de6 100644 --- a/src/js/filtering-context.js +++ b/src/js/filtering-context.js @@ -23,55 +23,146 @@ /******************************************************************************/ -µBlock.FilteringContext = function(other) { - if ( other instanceof µBlock.FilteringContext ) { - return this.fromFilteringContext(other); - } - this.tstamp = 0; - this.realm = ''; - this.id = undefined; - this.type = undefined; - this.url = undefined; - this.aliasURL = undefined; - this.hostname = undefined; - this.domain = undefined; - this.docId = undefined; - this.docOrigin = undefined; - this.docHostname = undefined; - this.docDomain = undefined; - this.tabId = undefined; - this.tabOrigin = undefined; - this.tabHostname = undefined; - this.tabDomain = undefined; - this.filter = undefined; +{ +// >>>>> start of local scope + +/******************************************************************************/ + +const originFromURI = µBlock.URI.originFromURI; +const hostnameFromURI = vAPI.hostnameFromURI; +const domainFromHostname = vAPI.domainFromHostname; + +/******************************************************************************/ + +// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webRequest/ResourceType + +// Long term, convert code wherever possible to work with integer-based type +// values -- the assumption being that integer operations are faster than +// string operations. + +const NO_TYPE = 0; +const BEACON = 1 << 0; +const CSP_REPORT = 1 << 1; +const FONT = 1 << 2; +const IMAGE = 1 << 4; +const IMAGESET = 1 << 4; +const MAIN_FRAME = 1 << 5; +const MEDIA = 1 << 6; +const OBJECT = 1 << 7; +const OBJECT_SUBREQUEST = 1 << 7; +const PING = 1 << 8; +const SCRIPT = 1 << 9; +const STYLESHEET = 1 << 10; +const SUB_FRAME = 1 << 11; +const WEBSOCKET = 1 << 12; +const XMLHTTPREQUEST = 1 << 13; +const INLINE_FONT = 1 << 14; +const INLINE_SCRIPT = 1 << 15; +const OTHER = 1 << 16; +const FRAME_ANY = MAIN_FRAME | SUB_FRAME; +const FONT_ANY = FONT | INLINE_FONT; +const INLINE_ANY = INLINE_FONT | INLINE_SCRIPT; +const PING_ANY = BEACON | CSP_REPORT | PING; +const SCRIPT_ANY = SCRIPT | INLINE_SCRIPT; + +const typeStrToIntMap = { + 'no_type': NO_TYPE, + 'beacon': BEACON, + 'csp_report': CSP_REPORT, + 'font': FONT, + 'image': IMAGE, + 'imageset': IMAGESET, + 'main_frame': MAIN_FRAME, + 'media': MEDIA, + 'object': OBJECT, + 'object_subrequest': OBJECT_SUBREQUEST, + 'ping': PING, + 'script': SCRIPT, + 'stylesheet': STYLESHEET, + 'sub_frame': SUB_FRAME, + 'websocket': WEBSOCKET, + 'xmlhttprequest': XMLHTTPREQUEST, + 'inline-font': INLINE_FONT, + 'inline-script': INLINE_SCRIPT, + 'other': OTHER, }; -µBlock.FilteringContext.prototype = { - fromTabId: function(tabId) { +/******************************************************************************/ + +const FilteringContext = class { + constructor(other) { + if ( other instanceof FilteringContext ) { + return this.fromFilteringContext(other); + } + this.tstamp = 0; + this.realm = ''; + this.id = undefined; + this.itype = 0; + this.stype = undefined; + this.url = undefined; + this.aliasURL = undefined; + this.hostname = undefined; + this.domain = undefined; + this.docId = -1; + this.frameId = -1; + this.docOrigin = undefined; + this.docHostname = undefined; + this.docDomain = undefined; + this.tabId = undefined; + this.tabOrigin = undefined; + this.tabHostname = undefined; + this.tabDomain = undefined; + this.redirectURL = undefined; + this.filter = undefined; + } + + get type() { + return this.stype; + } + + set type(a) { + this.itype = typeStrToIntMap[a] || NO_TYPE; + this.stype = a; + } + + isDocument() { + return (this.itype & FRAME_ANY) !== 0; + } + + isFont() { + return (this.itype & FONT_ANY) !== 0; + } + + fromTabId(tabId) { const tabContext = µBlock.tabContextManager.mustLookup(tabId); this.tabOrigin = tabContext.origin; this.tabHostname = tabContext.rootHostname; this.tabDomain = tabContext.rootDomain; this.tabId = tabContext.tabId; return this; - }, + } + // https://github.com/uBlockOrigin/uBlock-issues/issues/459 // In case of a request for frame and if ever no context is specified, // assume the origin of the context is the same as the request itself. - fromWebrequestDetails: function(details) { + fromWebrequestDetails(details) { const tabId = details.tabId; - if ( tabId > 0 && details.type === 'main_frame' ) { + this.type = details.type; + if ( this.itype === MAIN_FRAME && tabId > 0 ) { µBlock.tabContextManager.push(tabId, details.url); } - this.fromTabId(tabId); + this.fromTabId(tabId); // Must be called AFTER tab context management this.realm = ''; this.id = details.requestId; - this.type = details.type; this.setURL(details.url); this.aliasURL = details.aliasURL || undefined; - this.docId = details.type !== 'sub_frame' - ? details.frameId - : details.parentFrameId; + if ( this.itype !== SUB_FRAME ) { + this.docId = details.frameId; + this.frameId = -1; + } else { + this.docId = details.parentFrameId; + this.frameId = details.frameId; + } if ( this.tabId > 0 ) { if ( this.docId === 0 ) { this.docOrigin = this.tabOrigin; @@ -81,7 +172,7 @@ this.setDocOriginFromURL(details.documentUrl); } else { const pageStore = µBlock.pageStoreFromTabId(this.tabId); - const docStore = pageStore && pageStore.getFrame(this.docId); + const docStore = pageStore && pageStore.getFrameStore(this.docId); if ( docStore ) { this.setDocOriginFromURL(docStore.rawURL); } else { @@ -89,26 +180,29 @@ } } } else if ( details.documentUrl !== undefined ) { - const origin = this.originFromURI( + const origin = originFromURI( µBlock.normalizePageURL(0, details.documentUrl) ); this.setDocOrigin(origin).setTabOrigin(origin); - } else if ( this.docId === -1 || this.type.endsWith('_frame') ) { - const origin = this.originFromURI(this.url); + } else if ( this.docId === -1 || (this.itype & FRAME_ANY) !== 0 ) { + const origin = originFromURI(this.url); this.setDocOrigin(origin).setTabOrigin(origin); } else { this.setDocOrigin(this.tabOrigin); } + this.redirectURL = undefined; this.filter = undefined; return this; - }, - fromFilteringContext: function(other) { + } + + fromFilteringContext(other) { this.realm = other.realm; this.type = other.type; this.url = other.url; this.hostname = other.hostname; this.domain = other.domain; this.docId = other.docId; + this.frameId = other.frameId; this.docOrigin = other.docOrigin; this.docHostname = other.docHostname; this.docDomain = other.docDomain; @@ -116,92 +210,109 @@ this.tabOrigin = other.tabOrigin; this.tabHostname = other.tabHostname; this.tabDomain = other.tabDomain; + this.redirectURL = other.redirectURL; this.filter = undefined; return this; - }, - duplicate: function() { - return (new µBlock.FilteringContext(this)); - }, - setRealm: function(a) { + } + + duplicate() { + return (new FilteringContext(this)); + } + + setRealm(a) { this.realm = a; return this; - }, - setType: function(a) { + } + + setType(a) { this.type = a; return this; - }, - setURL: function(a) { + } + + setURL(a) { if ( a !== this.url ) { this.hostname = this.domain = undefined; this.url = a; } return this; - }, - getHostname: function() { + } + + getHostname() { if ( this.hostname === undefined ) { - this.hostname = this.hostnameFromURI(this.url); + this.hostname = hostnameFromURI(this.url); } return this.hostname; - }, - setHostname: function(a) { + } + + setHostname(a) { if ( a !== this.hostname ) { this.domain = undefined; this.hostname = a; } return this; - }, - getDomain: function() { + } + + getDomain() { if ( this.domain === undefined ) { - this.domain = this.domainFromHostname(this.getHostname()); + this.domain = domainFromHostname(this.getHostname()); } return this.domain; - }, - setDomain: function(a) { + } + + setDomain(a) { this.domain = a; return this; - }, - getDocOrigin: function() { + } + + getDocOrigin() { if ( this.docOrigin === undefined ) { this.docOrigin = this.tabOrigin; } return this.docOrigin; - }, - setDocOrigin: function(a) { + } + + setDocOrigin(a) { if ( a !== this.docOrigin ) { this.docHostname = this.docDomain = undefined; this.docOrigin = a; } return this; - }, - setDocOriginFromURL: function(a) { - return this.setDocOrigin(this.originFromURI(a)); - }, - getDocHostname: function() { + } + + setDocOriginFromURL(a) { + return this.setDocOrigin(originFromURI(a)); + } + + getDocHostname() { if ( this.docHostname === undefined ) { - this.docHostname = this.hostnameFromURI(this.getDocOrigin()); + this.docHostname = hostnameFromURI(this.getDocOrigin()); } return this.docHostname; - }, - setDocHostname: function(a) { + } + + setDocHostname(a) { if ( a !== this.docHostname ) { this.docDomain = undefined; this.docHostname = a; } return this; - }, - getDocDomain: function() { + } + + getDocDomain() { if ( this.docDomain === undefined ) { - this.docDomain = this.domainFromHostname(this.getDocHostname()); + this.docDomain = domainFromHostname(this.getDocHostname()); } return this.docDomain; - }, - setDocDomain: function(a) { + } + + setDocDomain(a) { this.docDomain = a; return this; - }, + } + // The idea is to minimize the amout of work done to figure out whether // the resource is 3rd-party to the document. - is3rdPartyToDoc: function() { + is3rdPartyToDoc() { let docDomain = this.getDocDomain(); if ( docDomain === '' ) { docDomain = this.docHostname; } if ( this.domain !== undefined && this.domain !== '' ) { @@ -212,12 +323,14 @@ const i = hostname.length - docDomain.length; if ( i === 0 ) { return false; } return hostname.charCodeAt(i - 1) !== 0x2E /* '.' */; - }, - setTabId: function(a) { + } + + setTabId(a) { this.tabId = a; return this; - }, - getTabOrigin: function() { + } + + getTabOrigin() { if ( this.tabOrigin === undefined ) { const tabContext = µBlock.tabContextManager.mustLookup(this.tabId); this.tabOrigin = tabContext.origin; @@ -225,43 +338,50 @@ this.tabDomain = tabContext.rootDomain; } return this.tabOrigin; - }, - setTabOrigin: function(a) { + } + + setTabOrigin(a) { if ( a !== this.tabOrigin ) { this.tabHostname = this.tabDomain = undefined; this.tabOrigin = a; } return this; - }, - setTabOriginFromURL: function(a) { - return this.setTabOrigin(this.originFromURI(a)); - }, - getTabHostname: function() { + } + + setTabOriginFromURL(a) { + return this.setTabOrigin(originFromURI(a)); + } + + getTabHostname() { if ( this.tabHostname === undefined ) { - this.tabHostname = this.hostnameFromURI(this.getTabOrigin()); + this.tabHostname = hostnameFromURI(this.getTabOrigin()); } return this.tabHostname; - }, - setTabHostname: function(a) { + } + + setTabHostname(a) { if ( a !== this.tabHostname ) { this.tabDomain = undefined; this.tabHostname = a; } return this; - }, - getTabDomain: function() { + } + + getTabDomain() { if ( this.tabDomain === undefined ) { - this.tabDomain = this.domainFromHostname(this.getTabHostname()); + this.tabDomain = domainFromHostname(this.getTabHostname()); } return this.tabDomain; - }, - setTabDomain: function(a) { + } + + setTabDomain(a) { this.docDomain = a; return this; - }, + } + // The idea is to minimize the amout of work done to figure out whether // the resource is 3rd-party to the top document. - is3rdPartyToTab: function() { + is3rdPartyToTab() { let tabDomain = this.getTabDomain(); if ( tabDomain === '' ) { tabDomain = this.tabHostname; } if ( this.domain !== undefined && this.domain !== '' ) { @@ -272,12 +392,38 @@ const i = hostname.length - tabDomain.length; if ( i === 0 ) { return false; } return hostname.charCodeAt(i - 1) !== 0x2E /* '.' */; - }, - setFilter: function(a) { + } + + setFilter(a) { this.filter = a; return this; - }, - toLogger: function() { + } + + pushFilter(a) { + if ( this.filter === undefined ) { + return this.setFilter(a); + } + if ( Array.isArray(this.filter) ) { + this.filter.push(a); + } else { + this.filter = [ this.filter, a ]; + } + return this; + } + + pushFilters(a) { + if ( this.filter === undefined ) { + return this.setFilter(a); + } + if ( Array.isArray(this.filter) ) { + this.filter.push(...a); + } else { + this.filter = [ this.filter, ...a ]; + } + return this; + } + + toLogger() { this.tstamp = Date.now(); if ( this.domain === undefined ) { void this.getDomain(); @@ -288,11 +434,49 @@ if ( this.tabDomain === undefined ) { void this.getTabDomain(); } - µBlock.logger.writeOne(this); - }, - originFromURI: µBlock.URI.originFromURI, - hostnameFromURI: µBlock.URI.hostnameFromURI, - domainFromHostname: µBlock.URI.domainFromHostname, + const logger = µBlock.logger; + const filters = this.filter; + // Many filters may have been applied to the current context + if ( Array.isArray(filters) === false ) { + return logger.writeOne(this); + } + for ( const filter of filters ) { + this.filter = filter; + logger.writeOne(this); + } + } }; -µBlock.filteringContext = new µBlock.FilteringContext(); +/******************************************************************************/ + +FilteringContext.prototype.BEACON = FilteringContext.BEACON = BEACON; +FilteringContext.prototype.CSP_REPORT = FilteringContext.CSP_REPORT = CSP_REPORT; +FilteringContext.prototype.FONT = FilteringContext.FONT = FONT; +FilteringContext.prototype.IMAGE = FilteringContext.IMAGE = IMAGE; +FilteringContext.prototype.IMAGESET = FilteringContext.IMAGESET = IMAGESET; +FilteringContext.prototype.MAIN_FRAME = FilteringContext.MAIN_FRAME = MAIN_FRAME; +FilteringContext.prototype.MEDIA = FilteringContext.MEDIA = MEDIA; +FilteringContext.prototype.OBJECT = FilteringContext.OBJECT = OBJECT; +FilteringContext.prototype.OBJECT_SUBREQUEST = FilteringContext.OBJECT_SUBREQUEST = OBJECT_SUBREQUEST; +FilteringContext.prototype.PING = FilteringContext.PING = PING; +FilteringContext.prototype.SCRIPT = FilteringContext.SCRIPT = SCRIPT; +FilteringContext.prototype.STYLESHEET = FilteringContext.STYLESHEET = STYLESHEET; +FilteringContext.prototype.SUB_FRAME = FilteringContext.SUB_FRAME = SUB_FRAME; +FilteringContext.prototype.WEBSOCKET = FilteringContext.WEBSOCKET = WEBSOCKET; +FilteringContext.prototype.XMLHTTPREQUEST = FilteringContext.XMLHTTPREQUEST = XMLHTTPREQUEST; +FilteringContext.prototype.INLINE_FONT = FilteringContext.INLINE_FONT = INLINE_FONT; +FilteringContext.prototype.INLINE_SCRIPT = FilteringContext.INLINE_SCRIPT = INLINE_SCRIPT; +FilteringContext.prototype.OTHER = FilteringContext.OTHER = OTHER; +FilteringContext.prototype.FRAME_ANY = FilteringContext.FRAME_ANY = FRAME_ANY; +FilteringContext.prototype.FONT_ANY = FilteringContext.FONT_ANY = FONT_ANY; +FilteringContext.prototype.INLINE_ANY = FilteringContext.INLINE_ANY = INLINE_ANY; +FilteringContext.prototype.PING_ANY = FilteringContext.PING_ANY = PING_ANY; +FilteringContext.prototype.SCRIPT_ANY = FilteringContext.SCRIPT_ANY = SCRIPT_ANY; + +/******************************************************************************/ + +µBlock.FilteringContext = FilteringContext; +µBlock.filteringContext = new FilteringContext(); + +// <<<<< end of local scope +} diff --git a/src/js/logger-ui.js b/src/js/logger-ui.js index 0dbba71e0cb53..7909116b8d039 100644 --- a/src/js/logger-ui.js +++ b/src/js/logger-ui.js @@ -215,6 +215,7 @@ const LogEntry = function(details) { this[prop] = details[prop]; } } + this.type = details.stype; if ( details.aliasURL !== undefined ) { this.aliased = true; } @@ -302,7 +303,13 @@ const processLoggerEntries = function(response) { if ( autoDeleteVoidedRows ) { continue; } parsed.voided = true; } - if ( parsed.type === 'main_frame' && parsed.aliased === false ) { + if ( + parsed.type === 'main_frame' && + parsed.aliased === false && ( + parsed.filter === undefined || + parsed.filter.source !== 'redirect' + ) + ) { const separator = createLogSeparator(parsed, unboxed.url); loggerEntries.unshift(separator); if ( rowFilterer.filterOne(separator) ) { @@ -1289,13 +1296,16 @@ const reloadTab = function(ev) { // Avoid duplicates if ( createdStaticFilters.hasOwnProperty(value) ) { return; } createdStaticFilters[value] = true; + // https://github.com/uBlockOrigin/uBlock-issues/issues/1281#issuecomment-704217175 + // TODO: + // Figure a way to use the actual document URL. Currently using + // a synthetic URL derived from the document hostname. if ( value !== '' ) { messaging.send('loggerUI', { what: 'createUserFilter', autoComment: true, filters: value, - origin: targetPageDomain, - pageDomain: targetPageDomain, + docURL: `https://${targetFrameHostname}/`, }); } updateWidgets(); @@ -1915,8 +1925,6 @@ const reloadTab = function(ev) { ); })(); -// https://www.youtube.com/watch?v=XyNYrmmdUd4 - /******************************************************************************/ /******************************************************************************/ diff --git a/src/js/logger.js b/src/js/logger.js index 8b5c05c3188ed..6e3741402dad7 100644 --- a/src/js/logger.js +++ b/src/js/logger.js @@ -62,10 +62,11 @@ ownerId: undefined, writeOne: function(details) { if ( buffer === null ) { return; } + const box = boxEntry(details); if ( writePtr === buffer.length ) { - buffer.push(boxEntry(details)); + buffer.push(box); } else { - buffer[writePtr] = boxEntry(details); + buffer[writePtr] = box; } writePtr += 1; }, diff --git a/src/js/messaging.js b/src/js/messaging.js index 597c36ed5dc64..66dfe98d7f2ec 100644 --- a/src/js/messaging.js +++ b/src/js/messaging.js @@ -40,20 +40,23 @@ var µb = µBlock; const µb = µBlock; -var getDomainNames = function(targets) { - var out = []; - var µburi = µb.URI; - var target, domain; - for ( var i = 0; i < targets.length; i++ ) { - target = targets[i]; - if ( target.indexOf('/') !== -1 ) { - domain = µburi.domainFromURI(target) || ''; - } else { - domain = µburi.domainFromHostname(target) || target; - } - out.push(domain); - } - return out; +const clickToLoad = function(request, sender) { + const { tabId, frameId } = sender; + if ( tabId === undefined || frameId === undefined ) { return false; } + const pageStore = µb.pageStoreFromTabId(tabId); + if ( pageStore === null ) { return false; } + pageStore.clickToLoad(frameId, request.frameURL); + return true; +}; + +const getDomainNames = function(targets) { + const µburi = µb.URI; + return targets.map(target => { + if ( typeof target !== 'string' ) { return ''; } + return target.indexOf('/') !== -1 + ? µburi.domainFromURI(target) || '' + : µburi.domainFromHostname(target) || target; + }); }; const onMessage = function(request, sender, callback) { @@ -104,13 +107,17 @@ const onMessage = function(request, sender, callback) { } // Sync - var response; + let response; switch ( request.what ) { case 'applyFilterListSelection': response = µb.applyFilterListSelection(request); break; + case 'clickToLoad': + response = clickToLoad(request, sender); + break; + case 'createUserFilter': µb.createUserFilters(request); break; @@ -192,7 +199,10 @@ const onMessage = function(request, sender, callback) { break; case 'uiStyles': - response = µb.hiddenSettings.uiStyles; + response = { + uiStyles: µb.hiddenSettings.uiStyles, + uiTheme: µb.hiddenSettings.uiTheme, + }; break; case 'userSettings': @@ -557,17 +567,11 @@ vAPI.messaging.listen({ const µb = µBlock; -const retrieveContentScriptParameters = function(senderDetails, request) { +const retrieveContentScriptParameters = function(sender, request) { if ( µb.readyToFilter !== true ) { return; } - const { url: senderURL, tabId, frameId } = senderDetails; - if ( - tabId === undefined || - frameId === undefined || - senderURL === undefined || - senderURL !== request.url && senderURL.startsWith('about:') === false - ) { - return; - } + const { tabId, frameId } = sender; + if ( tabId === undefined || frameId === undefined ) { return; } + const pageStore = µb.pageStoreFromTabId(tabId); if ( pageStore === null || pageStore.getNetFilteringSwitch() === false ) { return; @@ -662,8 +666,7 @@ const onMessage = function(request, sender, callback) { break; } - const senderDetails = µb.getMessageSenderDetails(sender); - const pageStore = µb.pageStoreFromTabId(senderDetails.tabId); + const pageStore = µb.pageStoreFromTabId(sender.tabId); // Sync let response; @@ -689,29 +692,29 @@ const onMessage = function(request, sender, callback) { break; case 'maybeGoodPopup': - µb.maybeGoodPopup.tabId = senderDetails.tabId; + µb.maybeGoodPopup.tabId = sender.tabId; µb.maybeGoodPopup.url = request.url; break; case 'shouldRenderNoscriptTags': if ( pageStore === null ) { break; } - const fctxt = µb.filteringContext.fromTabId(senderDetails.tabId); + const fctxt = µb.filteringContext.fromTabId(sender.tabId); if ( pageStore.filterScripting(fctxt, undefined) ) { - vAPI.tabs.executeScript(senderDetails.tabId, { + vAPI.tabs.executeScript(sender.tabId, { file: '/js/scriptlets/noscript-spoof.js', - frameId: senderDetails.frameId, + frameId: sender.frameId, runAt: 'document_end', }); } break; case 'retrieveContentScriptParameters': - response = retrieveContentScriptParameters(senderDetails, request); + response = retrieveContentScriptParameters(sender, request); break; case 'retrieveGenericCosmeticSelectors': - request.tabId = senderDetails.tabId; - request.frameId = senderDetails.frameId; + request.tabId = sender.tabId; + request.frameId = sender.frameId; response = { result: µb.cosmeticFilteringEngine.retrieveGenericSelectors(request), }; @@ -763,7 +766,7 @@ var onMessage = function(request, sender, callback) { mouse: µb.epickerArgs.mouse, zap: µb.epickerArgs.zap, eprom: µb.epickerArgs.eprom, - pickerURL: vAPI.getURL(`/web_accessible_resources/epicker-ui.html${vAPI.warSecret()}`), + pickerURL: vAPI.getURL(`/web_accessible_resources/epicker-ui.html?secret=${vAPI.warSecret()}`), }; µb.epickerArgs.target = ''; break; @@ -921,7 +924,7 @@ const backupUserData = async function() { version: vAPI.app.version, userSettings: µb.userSettings, selectedFilterLists: µb.selectedFilterLists, - hiddenSettings: µb.hiddenSettings, + hiddenSettings: µb.getModifiedHiddenSettings(), whitelist: µb.arrayFromWhitelist(µb.netWhitelist), // String representation eventually to be deprecated netWhitelist: µb.stringFromWhitelist(µb.netWhitelist), @@ -962,12 +965,24 @@ const restoreUserData = async function(request) { // Restore user data vAPI.storage.set(userData.userSettings); + + // Restore advanced settings. let hiddenSettings = userData.hiddenSettings; if ( hiddenSettings instanceof Object === false ) { hiddenSettings = µBlock.hiddenSettingsFromString( userData.hiddenSettingsString || '' ); } + // Discard unknown setting or setting with default value. + for ( const key in hiddenSettings ) { + if ( + µb.hiddenSettingsDefault.hasOwnProperty(key) === false || + hiddenSettings[key] === µb.hiddenSettingsDefault[key] + ) { + delete hiddenSettings[key]; + } + } + // Whitelist directives can be represented as an array or as a // (eventually to be deprecated) string. let whitelist = userData.whitelist; @@ -979,7 +994,7 @@ const restoreUserData = async function(request) { whitelist = userData.netWhitelist.split('\n'); } vAPI.storage.set({ - hiddenSettings: hiddenSettings, + hiddenSettings, netWhitelist: whitelist || [], dynamicFilteringString: userData.dynamicFilteringString || '', urlFilteringString: userData.urlFilteringString || '', @@ -1210,6 +1225,7 @@ const onMessage = function(request, sender, callback) { redirectResources: µb.redirectEngine.getResourceDetails(), preparseDirectiveTokens: µb.preparseDirectives.getTokens(), preparseDirectiveHints: µb.preparseDirectives.getHints(), + expertMode: µb.hiddenSettings.filterAuthorMode, }; break; @@ -1478,8 +1494,8 @@ vAPI.messaging.listen({ { // >>>>> start of local scope -var onMessage = function(request, sender, callback) { - const tabId = sender && sender.tab ? sender.tab.id : 0; +const onMessage = function(request, sender, callback) { + const tabId = sender.tabId || 0; // Async switch ( request.what ) { @@ -1564,10 +1580,12 @@ const logCSPViolations = function(pageStore, request) { cspData = new Map(); const staticDirectives = - µb.staticNetFilteringEngine.matchAndFetchData(fctxt, 'csp'); - for ( const directive of staticDirectives ) { - if ( directive.result !== 1 ) { continue; } - cspData.set(directive.getData('csp'), directive.logData()); + µb.staticNetFilteringEngine.matchAndFetchModifiers(fctxt, 'csp'); + if ( staticDirectives !== undefined ) { + for ( const directive of staticDirectives ) { + if ( directive.result !== 1 ) { continue; } + cspData.set(directive.value, directive.logData()); + } } fctxt.type = 'inline-script'; @@ -1630,8 +1648,8 @@ logCSPViolations.policyDirectiveToTypeMap = new Map([ ]); const onMessage = function(request, sender, callback) { - let tabId = sender && sender.tab ? sender.tab.id : 0; - let pageStore = µb.pageStoreFromTabId(tabId); + const tabId = sender.tabId || 0; + const pageStore = µb.pageStoreFromTabId(tabId); // Async switch ( request.what ) { @@ -1668,7 +1686,7 @@ const onMessage = function(request, sender, callback) { case 'temporarilyAllowLargeMediaElement': if ( pageStore !== null ) { - pageStore.allowLargeMediaElementsUntil = Date.now() + 2000; + pageStore.allowLargeMediaElementsUntil = Date.now() + 5000; } break; diff --git a/src/js/pagestore.js b/src/js/pagestore.js index 333a9403cf70e..07ab8c33df2a0 100644 --- a/src/js/pagestore.js +++ b/src/js/pagestore.js @@ -54,18 +54,21 @@ const NetFilteringResultCache = class { return this; } + // https://github.com/gorhill/uBlock/issues/3619 + // Don't collapse redirected resources rememberResult(fctxt, result) { if ( fctxt.tabId <= 0 ) { return; } if ( this.results.size === 0 ) { this.pruneAsync(); } - const key = fctxt.getDocHostname() + ' ' + fctxt.type + ' ' + fctxt.url; + const key = `${fctxt.getDocHostname()} ${fctxt.type} ${fctxt.url}`; this.results.set(key, { - result: result, + result, + redirectURL: fctxt.redirectURL, logData: fctxt.filter, tstamp: Date.now() }); - if ( result !== 1 ) { return; } + if ( result !== 1 || fctxt.redirectURL !== undefined ) { return; } const now = Date.now(); this.blocked.set(key, now); this.hash = now; @@ -76,14 +79,21 @@ const NetFilteringResultCache = class { if ( this.blocked.size === 0 ) { this.pruneAsync(); } + if ( fctxt.redirectURL !== undefined ) { return; } const now = Date.now(); this.blocked.set( - fctxt.getDocHostname() + ' ' + fctxt.type + ' ' + fctxt.url, + `${fctxt.getDocHostname()} ${fctxt.type} ${fctxt.url}`, now ); this.hash = now; } + forgetResult(docHostname, type, url) { + const key = `${docHostname} ${type} ${url}`; + this.results.delete(key); + this.blocked.delete(key); + } + empty() { this.blocked.clear(); this.results.clear(); @@ -124,11 +134,23 @@ const NetFilteringResultCache = class { } lookupResult(fctxt) { - return this.results.get( + const entry = this.results.get( fctxt.getDocHostname() + ' ' + fctxt.type + ' ' + fctxt.url ); + if ( entry === undefined ) { return; } + // We need to use a new WAR secret if one is present since WAR secrets + // can only be used once. + if ( + entry.redirectURL !== undefined && + entry.redirectURL.startsWith(this.extensionOriginURL) + ) { + const redirectURL = new URL(entry.redirectURL); + redirectURL.searchParams.set('secret', vAPI.warSecret()); + entry.redirectURL = redirectURL.href; + } + return entry; } lookupAllBlocked(hostname) { @@ -148,6 +170,7 @@ const NetFilteringResultCache = class { }; NetFilteringResultCache.prototype.shelfLife = 15000; +NetFilteringResultCache.prototype.extensionOriginURL = vAPI.getURL('/'); /******************************************************************************/ @@ -165,6 +188,7 @@ const FrameStore = class { init(frameURL) { this.t0 = Date.now(); this.exceptCname = undefined; + this.clickToLoad = false; this.rawURL = frameURL; if ( frameURL !== undefined ) { this.hostname = vAPI.hostnameFromURI(frameURL); @@ -233,7 +257,7 @@ const PageStore = class { typeof this.allowLargeMediaElementsUntil !== 'number' || tabContext.rootHostname !== this.tabHostname ) { - this.allowLargeMediaElementsUntil = 0; + this.allowLargeMediaElementsUntil = Date.now(); } this.tabHostname = tabContext.rootHostname; @@ -249,23 +273,12 @@ const PageStore = class { this.largeMediaCount = 0; this.largeMediaTimer = null; this.internalRedirectionCount = 0; + this.allowLargeMediaElementsRegex = undefined; this.extraData.clear(); this.frameAddCount = 0; this.frames = new Map(); - this.setFrame(0, tabContext.rawURL); - - // The current filtering context is cloned because: - // - We may be called with or without the current context having been - // initialized. - // - If it has been initialized, we do not want to change the state - // of the current context. - const fctxt = µb.logger.enabled - ? µb.filteringContext - .duplicate() - .fromTabId(tabId) - .setURL(tabContext.rawURL) - : undefined; + this.setFrameURL(0, tabContext.rawURL); // https://github.com/uBlockOrigin/uBlock-issues/issues/314 const masterSwitch = tabContext.getNetFilteringSwitch(); @@ -280,10 +293,14 @@ const PageStore = class { µb.logger.enabled && context === 'tabCommitted' ) { - fctxt.setRealm('cosmetic') - .setType('dom') - .setFilter(µb.sessionSwitches.toLogData()) - .toLogger(); + µb.filteringContext + .duplicate() + .fromTabId(tabId) + .setURL(tabContext.rawURL) + .setRealm('cosmetic') + .setType('dom') + .setFilter(µb.sessionSwitches.toLogData()) + .toLogger(); } return this; @@ -308,7 +325,7 @@ const PageStore = class { // As part of https://github.com/chrisaljoudi/uBlock/issues/405 // URL changed, force a re-evaluation of filtering switch this.rawURL = tabContext.rawURL; - this.setFrame(0, this.rawURL); + this.setFrameURL(0, this.rawURL); return this; } @@ -328,7 +345,8 @@ const PageStore = class { this.rawURL = ''; this.hostnameToCountMap = null; this.netFilteringCache.empty(); - this.allowLargeMediaElementsUntil = 0; + this.allowLargeMediaElementsUntil = Date.now(); + this.allowLargeMediaElementsRegex = undefined; if ( this.largeMediaTimer !== null ) { clearTimeout(this.largeMediaTimer); this.largeMediaTimer = null; @@ -353,20 +371,23 @@ const PageStore = class { this.frames.clear(); } - getFrame(frameId) { + getFrameStore(frameId) { return this.frames.get(frameId) || null; } - setFrame(frameId, frameURL) { - const frameStore = this.frames.get(frameId); + setFrameURL(frameId, frameURL) { + let frameStore = this.frames.get(frameId); if ( frameStore !== undefined ) { frameStore.init(frameURL); - return; + } else { + frameStore = FrameStore.factory(frameURL); + this.frames.set(frameId, frameStore); + this.frameAddCount += 1; + if ( (this.frameAddCount & 0b111111) === 0 ) { + this.pruneFrames(); + } } - this.frames.set(frameId, FrameStore.factory(frameURL)); - this.frameAddCount += 1; - if ( (this.frameAddCount & 0b111111) !== 0 ) { return; } - this.pruneFrames(); + return frameStore; } // There is no event to tell us a specific subframe has been removed from @@ -424,7 +445,12 @@ const PageStore = class { temporarilyAllowLargeMediaElements(state) { this.largeMediaCount = 0; µb.contextMenu.update(this.tabId); - this.allowLargeMediaElementsUntil = state ? Date.now() + 86400000 : 0; + if ( state ) { + this.allowLargeMediaElementsUntil = 0; + this.allowLargeMediaElementsRegex = undefined; + } else { + this.allowLargeMediaElementsUntil = Date.now(); + } µb.scriptlets.injectDeep(this.tabId, 'load-large-media-all'); } @@ -519,48 +545,54 @@ const PageStore = class { filterRequest(fctxt) { fctxt.filter = undefined; + fctxt.redirectURL = undefined; if ( this.getNetFilteringSwitch(fctxt) === false ) { return 0; } - const requestType = fctxt.type; - if ( - requestType === 'csp_report' && + fctxt.itype === fctxt.CSP_REPORT && this.filterCSPReport(fctxt) === 1 ) { return 1; } - if ( requestType.endsWith('font') && this.filterFont(fctxt) === 1 ) { + if ( + (fctxt.itype & fctxt.FONT_ANY) !== 0 && + this.filterFont(fctxt) === 1 ) + { return 1; } if ( - requestType === 'script' && + fctxt.itype === fctxt.SCRIPT && this.filterScripting(fctxt, true) === 1 ) { return 1; } - const cacheableResult = this.cacheableResults.has(requestType); + const cacheableResult = this.cacheableResults.has(fctxt.itype); if ( cacheableResult ) { const entry = this.netFilteringCache.lookupResult(fctxt); if ( entry !== undefined ) { + fctxt.redirectURL = entry.redirectURL; fctxt.filter = entry.logData; return entry.result; } } + const requestType = fctxt.type; + const loggerEnabled = µb.logger.enabled; + // Dynamic URL filtering. let result = µb.sessionURLFiltering.evaluateZ( fctxt.getTabHostname(), fctxt.url, requestType ); - if ( result !== 0 && µb.logger.enabled ) { + if ( result !== 0 && loggerEnabled ) { fctxt.filter = µb.sessionURLFiltering.toLogData(); } @@ -581,18 +613,17 @@ const PageStore = class { fctxt.getHostname(), requestType ); - if ( result !== 0 && result !== 3 && µb.logger.enabled ) { + if ( result !== 0 && result !== 3 && loggerEnabled ) { fctxt.filter = µb.sessionFirewall.toLogData(); } } // Static filtering has lowest precedence. - if ( result === 0 || result === 3 || result === 4) { - const snfe = µb.staticNetFilteringEngine; - const updatedResult = snfe.matchString(fctxt); - result = result === 4 ? 4 : updatedResult; + const snfe = µb.staticNetFilteringEngine; + if ( result === 0 || result === 3 ) { + result = snfe.matchString(fctxt); if ( result !== 0 ) { - if ( µb.logger.enabled ) { + if ( loggerEnabled ) { fctxt.filter = snfe.toLogData(); } // https://github.com/uBlockOrigin/uBlock-issues/issues/943 @@ -612,18 +643,71 @@ const PageStore = class { } } + // Click-to-load? + // When frameId is not -1, the resource is always sub_frame. + if ( result === 1 && fctxt.frameId !== -1 ) { + const frameStore = this.getFrameStore(fctxt.frameId); + if ( frameStore !== null && frameStore.clickToLoad ) { + result = 2; + if ( loggerEnabled ) { + fctxt.pushFilter({ + result, + source: 'network', + raw: 'click-to-load', + }); + } + } + } + + // Modifier(s)? + // A modifier is an action which transform the original network request. + // https://github.com/gorhill/uBlock/issues/949 + // Redirect blocked request? + // https://github.com/uBlockOrigin/uBlock-issues/issues/760 + // Redirect non-blocked request? + if ( (fctxt.itype & fctxt.INLINE_ANY) === 0 ) { + if ( result === 1 ) { + this.redirectBlockedRequest(fctxt); + } else if ( snfe.hasQuery(fctxt) ) { + this.redirectNonBlockedRequest(fctxt); + } + } + if ( cacheableResult ) { this.netFilteringCache.rememberResult(fctxt, result); - } else if ( - result === 1 && - this.collapsibleResources.has(requestType) - ) { - this.netFilteringCache.rememberBlock(fctxt, true); + } else if ( result === 1 && this.collapsibleResources.has(fctxt.itype) ) { + this.netFilteringCache.rememberBlock(fctxt); } return result; } + redirectBlockedRequest(fctxt) { + if ( µb.hiddenSettings.ignoreRedirectFilters === true ) { return; } + const directive = µb.staticNetFilteringEngine.redirectRequest(fctxt); + if ( directive === undefined ) { return; } + this.internalRedirectionCount += 1; + if ( µb.logger.enabled !== true ) { return; } + fctxt.pushFilter(directive.logData()); + if ( fctxt.redirectURL === undefined ) { return; } + fctxt.pushFilter({ + source: 'redirect', + raw: µb.redirectEngine.resourceNameRegister + }); + } + + redirectNonBlockedRequest(fctxt) { + const directives = µb.staticNetFilteringEngine.filterQuery(fctxt); + if ( directives === undefined ) { return; } + if ( µb.logger.enabled !== true ) { return; } + fctxt.pushFilters(directives.map(a => a.logData())); + if ( fctxt.redirectURL === undefined ) { return; } + fctxt.pushFilter({ + source: 'redirect', + raw: fctxt.redirectURL + }); + } + filterCSPReport(fctxt) { if ( µb.sessionSwitches.evaluateZ( @@ -640,7 +724,7 @@ const PageStore = class { } filterFont(fctxt) { - if ( fctxt.type === 'font' ) { + if ( fctxt.itype === fctxt.FONT ) { this.remoteFontCount += 1; } if ( @@ -681,7 +765,23 @@ const PageStore = class { filterLargeMediaElement(fctxt, size) { fctxt.filter = undefined; + if ( this.allowLargeMediaElementsUntil === 0 ) { + return 0; + } + // Disregard large media elements previously allowed: for example, to + // seek inside a previously allowed audio/video. + if ( + this.allowLargeMediaElementsRegex instanceof RegExp && + this.allowLargeMediaElementsRegex.test(fctxt.url) + ) { + return 0; + } if ( Date.now() < this.allowLargeMediaElementsUntil ) { + const sources = this.allowLargeMediaElementsRegex instanceof RegExp + ? [ this.allowLargeMediaElementsRegex.source ] + : []; + sources.push('^' + µb.escapeRegex(fctxt.url)); + this.allowLargeMediaElementsRegex = new RegExp(sources.join('|')); return 0; } if ( @@ -690,6 +790,7 @@ const PageStore = class { fctxt.getTabHostname() ) !== true ) { + this.allowLargeMediaElementsUntil = 0; return 0; } if ( (size >>> 10) < µb.userSettings.largeMediaSize ) { @@ -711,11 +812,24 @@ const PageStore = class { return 1; } + clickToLoad(frameId, frameURL) { + let frameStore = this.getFrameStore(frameId); + if ( frameStore === null ) { + frameStore = this.setFrameURL(frameId, frameURL); + } + this.netFilteringCache.forgetResult( + this.tabHostname, + 'sub_frame', + frameURL + ); + frameStore.clickToLoad = true; + } + shouldExceptCname(fctxt) { let exceptCname; let frameStore; if ( fctxt.docId !== undefined ) { - frameStore = this.getFrame(fctxt.docId); + frameStore = this.getFrameStore(fctxt.docId); if ( frameStore instanceof Object ) { exceptCname = frameStore.exceptCname; } @@ -740,7 +854,7 @@ const PageStore = class { } if ( exceptCname === false ) { return false; } if ( exceptCname instanceof Object ) { - fctxt.setFilter(exceptCname); + fctxt.pushFilter(exceptCname); } return true; } @@ -758,8 +872,7 @@ const PageStore = class { if ( Array.isArray(resources) && resources.length !== 0 ) { for ( const resource of resources ) { this.filterRequest( - fctxt.setType(resource.type) - .setURL(resource.url) + fctxt.setType(resource.type).setURL(resource.url) ); } } @@ -771,14 +884,14 @@ const PageStore = class { }; PageStore.prototype.cacheableResults = new Set([ - 'sub_frame', + µb.FilteringContext.SUB_FRAME, ]); PageStore.prototype.collapsibleResources = new Set([ - 'image', - 'media', - 'object', - 'sub_frame', + µb.FilteringContext.IMAGE, + µb.FilteringContext.MEDIA, + µb.FilteringContext.OBJECT, + µb.FilteringContext.SUB_FRAME, ]); µb.PageStore = PageStore; diff --git a/src/js/popup-fenix.js b/src/js/popup-fenix.js index c8f543c58dd5e..37e02846547b3 100644 --- a/src/js/popup-fenix.js +++ b/src/js/popup-fenix.js @@ -1027,7 +1027,7 @@ uDom('[data-i18n="popupAnyRulePrompt"]').on('click', ev => { messaging.send('popupPanel', { what: 'gotoURL', details: { - url: `popup-fenix.html?tabId=${popupData.tabId}`, + url: `popup-fenix.html?tabId=${popupData.tabId}&intab=1`, select: true, index: -1, }, @@ -1260,6 +1260,9 @@ const getPopupData = async function(tabId) { panes.prepend(sticky); } } + if ( selfURL.searchParams.get('intab') !== null ) { + root.classList.add('intab'); + } await nextFrames(1); document.body.classList.remove('loading'); }; diff --git a/src/js/redirect-engine.js b/src/js/redirect-engine.js index fa3f26db02dd2..95db7673dbd0a 100644 --- a/src/js/redirect-engine.js +++ b/src/js/redirect-engine.js @@ -67,6 +67,9 @@ const redirectableResources = new Map([ [ 'chartbeat.js', { alias: 'static.chartbeat.com/chartbeat.js', } ], + [ 'click2load.html', { + params: [ 'url' ], + } ], [ 'doubleclick_instream_ad_status.js', { alias: 'doubleclick.net/instream/ad_status.js', } ], @@ -191,6 +194,7 @@ const RedirectEntry = class { this.mime = ''; this.data = ''; this.warURL = undefined; + this.params = undefined; } // Prevent redirection to web accessible resources when the request is @@ -208,7 +212,15 @@ const RedirectEntry = class { fctxt instanceof Object && fctxt.type !== 'xmlhttprequest' ) { - return `${this.warURL}${vAPI.warSecret()}`; + let url = `${this.warURL}?secret=${vAPI.warSecret()}`; + if ( this.params !== undefined ) { + for ( const name of this.params ) { + const value = fctxt[name]; + if ( value === undefined ) { continue; } + url += `&${name}=${encodeURIComponent(value)}`; + } + } + return url; } if ( this.data === undefined ) { return; } // https://github.com/uBlockOrigin/uBlock-issues/issues/701 @@ -251,6 +263,7 @@ const RedirectEntry = class { r.mime = selfie.mime; r.data = selfie.data; r.warURL = selfie.warURL; + r.params = selfie.params; return r; } }; @@ -262,24 +275,13 @@ const RedirectEngine = function() { this.aliases = new Map(); this.resources = new Map(); this.reset(); + this.modifyTime = Date.now(); this.resourceNameRegister = ''; }; /******************************************************************************/ RedirectEngine.prototype.reset = function() { - this.rules = new Map(); - this.ruleSources = new Set(); - this.ruleDestinations = new Set(); - this.resetCache(); - this.modifyTime = Date.now(); -}; - -RedirectEngine.prototype.resetCache = function() { - this._src = ''; - this._srcAll = [ '*' ]; - this._des = ''; - this._desAll = [ '*' ]; }; /******************************************************************************/ @@ -289,301 +291,25 @@ RedirectEngine.prototype.freeze = function() { /******************************************************************************/ -RedirectEngine.prototype.toBroaderHostname = function(hostname) { - const pos = hostname.indexOf('.'); - if ( pos !== -1 ) { - return hostname.slice(pos + 1); - } - return hostname !== '*' ? '*' : ''; -}; - -/******************************************************************************/ - -RedirectEngine.prototype.decomposeHostname = function(hn, dict, out) { - let i = 0; - for (;;) { - if ( dict.has(hn) ) { - out[i] = hn; i += 1; - } - hn = this.toBroaderHostname(hn); - if ( hn === '' ) { break; } - } - out.length = i; -}; - -/******************************************************************************/ - -RedirectEngine.prototype.lookup = function(fctxt) { - const src = fctxt.getDocHostname(); - const des = fctxt.getHostname(); - const type = fctxt.type; - if ( src !== this._src ) { - this._src = src; - this.decomposeHostname(src, this.ruleSources, this._srcAll); - } - if ( this._srcAll.length === 0 ) { return; } - if ( des !== this._des ) { - this._des = des; - this.decomposeHostname(des, this.ruleDestinations, this._desAll); - } - if ( this._desAll.length === 0 ) { return; } - const reqURL = fctxt.url; - for ( const src of this._srcAll ) { - for ( const des of this._desAll ) { - let entries = this.rules.get(`${src} ${des} ${type}`); - if ( entries !== undefined ) { - const rule = this.lookupRule(entries, reqURL); - if ( rule !== undefined ) { return rule; } - } - entries = this.rules.get(`${src} ${des} *`); - if ( entries !== undefined ) { - const rule = this.lookupRule(entries, reqURL); - if ( rule !== undefined ) { return rule; } - } - } - } -}; - -RedirectEngine.prototype.lookupRule = function(entries, reqURL) { - for ( const entry of entries ) { - if ( entry.pat instanceof RegExp === false ) { - entry.pat = new RegExp(entry.pat, 'i'); - } - if ( entry.pat.test(reqURL) ) { - return entry; - } - } -}; - -/******************************************************************************/ - -RedirectEngine.prototype.toURL = function(fctxt) { - const rule = this.lookup(fctxt); - if ( rule === undefined ) { return; } - let token = this.resourceNameRegister = rule.tok; +RedirectEngine.prototype.tokenToURL = function(fctxt, token) { const asDataURI = token.charCodeAt(0) === 0x25 /* '%' */; if ( asDataURI ) { token = token.slice(1); } const entry = this.resources.get(this.aliases.get(token) || token); - if ( entry !== undefined ) { - return entry.toURL(fctxt, asDataURI); - } -}; - -/******************************************************************************/ - -RedirectEngine.prototype.addRule = function(src, des, type, pattern, redirect) { - this.ruleSources.add(src); - this.ruleDestinations.add(des); - const key = `${src} ${des} ${type}`, - entries = this.rules.get(key); - if ( entries === undefined ) { - this.rules.set(key, [ { tok: redirect, pat: pattern } ]); - this.modifyTime = Date.now(); - return; - } - let entry; - for ( var i = 0, n = entries.length; i < n; i++ ) { - entry = entries[i]; - if ( redirect === entry.tok ) { break; } - } - if ( i === n ) { - entries.push({ tok: redirect, pat: pattern }); - return; - } - let p = entry.pat; - if ( p instanceof RegExp ) { - p = p.source; - } - // Duplicate? - let pos = p.indexOf(pattern); - if ( pos !== -1 ) { - if ( pos === 0 || p.charAt(pos - 1) === '|' ) { - pos += pattern.length; - if ( pos === p.length || p.charAt(pos) === '|' ) { return; } - } - } - entry.pat = p + '|' + pattern; -}; - -/******************************************************************************/ - -RedirectEngine.prototype.fromCompiledRule = function(line) { - const fields = line.split('\t'); - if ( fields.length !== 5 ) { return; } - this.addRule(fields[0], fields[1], fields[2], fields[3], fields[4]); -}; - -/******************************************************************************/ - -RedirectEngine.prototype.compileRuleFromStaticFilter = function(line) { - const matches = this.reFilterParser.exec(line); - if ( matches === null || matches.length !== 4 ) { return; } - - const des = matches[1] || ''; - - // https://github.com/uBlockOrigin/uBlock-issues/issues/572 - // Extract best possible hostname. - let deshn = des; - let pos = deshn.lastIndexOf('*'); - if ( pos !== -1 ) { - deshn = deshn.slice(pos + 1); - pos = deshn.indexOf('.'); - if ( pos !== -1 ) { - deshn = deshn.slice(pos + 1); - } else { - deshn = ''; - } - } - - const path = matches[2] || ''; - let pattern = - des - .replace(/\*/g, '[\\w.%-]*') - .replace(/\./g, '\\.') + - path - .replace(/\|$/, '$') - .replace(/[.+?{}()|[\]\/\\]/g, '\\$&') - .replace(/\^/g, '[^\\w.%-]') - .replace(/\*/g, '.*?'); - if ( pattern === '' ) { - pattern = '^'; - } - - let type, - redirect = '', - srchns = []; - for ( const option of matches[3].trim().split(/,/) ) { - if ( option.startsWith('redirect=') ) { - redirect = option.slice(9); - continue; - } - if ( option.startsWith('redirect-rule=') ) { - redirect = option.slice(14); - continue; - } - if ( option === 'empty' ) { - redirect = 'empty'; - continue; - } - if ( option === 'mp4' ) { - redirect = 'noopmp4-1s'; - continue; - } - if ( option.startsWith('domain=') ) { - srchns = option.slice(7).split('|'); - continue; - } - if ( (option === 'first-party' || option === '1p') && deshn !== '' ) { - srchns.push(µBlock.URI.domainFromHostname(deshn) || deshn); - continue; - } - // One and only one type must be specified. - if ( this.supportedTypes.has(option) ) { - if ( type !== undefined ) { return; } - type = this.supportedTypes.get(option); - continue; - } - } - - // Need a resource token. - if ( redirect === '' ) { return; } - - // Need one single type -- not negated. - if ( type === undefined ) { - if ( redirect === 'empty' ) { - type = '*'; - } else if ( redirect === 'noopmp4-1s' ) { - type = 'media'; - } else { - return; - } - } - - if ( deshn === '' ) { - deshn = '*'; - } - - if ( srchns.length === 0 ) { - srchns.push('*'); - } - - const out = []; - for ( const srchn of srchns ) { - if ( srchn === '' ) { continue; } - if ( srchn.startsWith('~') ) { continue; } - out.push(`${srchn}\t${deshn}\t${type}\t${pattern}\t${redirect}`); - } - - if ( out.length === 0 ) { return; } - - return out; + if ( entry === undefined ) { return; } + this.resourceNameRegister = token; + return entry.toURL(fctxt, asDataURI); }; /******************************************************************************/ -RedirectEngine.prototype.reFilterParser = /^(?:\|\|([^\/:?#^]+)|\*?)([^$]+)?\$([^$]+)$/; - -RedirectEngine.prototype.supportedTypes = new Map([ - [ 'css', 'stylesheet' ], - [ 'font', 'font' ], - [ 'image', 'image' ], - [ 'media', 'media' ], - [ 'object', 'object' ], - [ 'script', 'script' ], - [ 'stylesheet', 'stylesheet' ], - [ 'frame', 'sub_frame' ], - [ 'subdocument', 'sub_frame' ], - [ 'xhr', 'xmlhttprequest' ], - [ 'xmlhttprequest', 'xmlhttprequest' ], -]); - -/******************************************************************************/ - -RedirectEngine.prototype.toSelfie = function(path) { - // Because rules may contains RegExp instances, we need to manually - // convert it to a serializable format. The serialized format must be - // suitable to be used as an argument to the Map() constructor. - const rules = []; - for ( const item of this.rules ) { - const rule = [ item[0], [] ]; - const entries = item[1]; - let i = entries.length; - while ( i-- ) { - const entry = entries[i]; - rule[1].push({ - tok: entry.tok, - pat: entry.pat instanceof RegExp ? entry.pat.source : entry.pat - }); - } - rules.push(rule); - } - return µBlock.assets.put( - `${path}/main`, - JSON.stringify({ - rules: rules, - ruleSources: Array.from(this.ruleSources), - ruleDestinations: Array.from(this.ruleDestinations) - }) - ); +RedirectEngine.prototype.toSelfie = async function() { }; /******************************************************************************/ -RedirectEngine.prototype.fromSelfie = async function(path) { - const result = await µBlock.assets.get(`${path}/main`); - let selfie; - try { - selfie = JSON.parse(result.content); - } catch (ex) { - } - if ( selfie instanceof Object === false ) { return false; } - this.rules = new Map(selfie.rules); - this.ruleSources = new Set(selfie.ruleSources); - this.ruleDestinations = new Set(selfie.ruleDestinations); - this.resetCache(); - this.modifyTime = Date.now(); +RedirectEngine.prototype.fromSelfie = async function() { return true; }; @@ -721,6 +447,7 @@ RedirectEngine.prototype.loadBuiltinResources = function() { mime: mimeFromName(name), data, warURL: vAPI.getURL(`/web_accessible_resources/${name}`), + params: details.params, }); this.resources.set(name, entry); if ( details.alias !== undefined ) { @@ -762,7 +489,7 @@ RedirectEngine.prototype.loadBuiltinResources = function() { } fetches.push( µBlock.assets.fetch( - `/web_accessible_resources/${name}${vAPI.warSecret()}`, + `/web_accessible_resources/${name}?secret=${vAPI.warSecret()}`, { responseType: details.data } ).then( result => process(result) @@ -776,7 +503,9 @@ RedirectEngine.prototype.loadBuiltinResources = function() { /******************************************************************************/ RedirectEngine.prototype.getResourceDetails = function() { - const out = new Map(); + const out = new Map([ + [ 'none', { canInject: false, canRedirect: true, aliasOf: '' } ], + ]); for ( const [ name, entry ] of this.resources ) { out.set(name, { canInject: typeof entry.data === 'string', @@ -835,9 +564,6 @@ RedirectEngine.prototype.resourcesFromSelfie = async function() { RedirectEngine.prototype.invalidateResourcesSelfie = function() { µBlock.assets.remove('compiled/redirectEngine/resources'); - - // TODO: obsolete, remove eventually - µBlock.cacheStorage.remove('resourcesSelfie'); }; /******************************************************************************/ diff --git a/src/js/reverselookup.js b/src/js/reverselookup.js index 7750810270d80..c0c51eb74b634 100644 --- a/src/js/reverselookup.js +++ b/src/js/reverselookup.js @@ -404,7 +404,7 @@ if ( const µb = µBlock; const writer = new µb.CompiledLineIO.Writer(); const parser = new vAPI.StaticFilteringParser(); - parser.setMaxTokenLength(µb.urlTokenizer.MAX_TOKEN_LENGTH); + parser.setMaxTokenLength(µb.staticNetFilteringEngine.MAX_TOKEN_LENGTH); parser.analyze(rawFilter); if ( µb.staticNetFilteringEngine.compile(parser, writer) === false ) { diff --git a/src/js/scriptlets/epicker.js b/src/js/scriptlets/epicker.js index 311c226f312ba..f0b37e3e6bd5c 100644 --- a/src/js/scriptlets/epicker.js +++ b/src/js/scriptlets/epicker.js @@ -805,7 +805,8 @@ const filterToDOMInterface = (( ) => { if ( cssSelectors.size !== 0 ) { vAPI.domFilterer.addCSSRule( Array.from(cssSelectors), - vAPI.hideStyle + vAPI.hideStyle, + { mustInject: true } ); } if ( proceduralSelectors.size !== 0 ) { @@ -820,21 +821,33 @@ const filterToDOMInterface = (( ) => { /******************************************************************************/ -const onOptmizeCandidate = function(details) { - const { paths } = details; - let count = Number.MAX_SAFE_INTEGER; - let selector = ''; - for ( let i = 0, n = paths.length; i < n; i++ ) { - const s = paths.slice(n - i - 1).join(''); - const elems = document.querySelectorAll(s); - if ( elems.length < count ) { - selector = s; - count = elems.length; +const onOptmizeCandidates = function(details) { + const { candidates } = details; + const results = []; + for ( const paths of candidates ) { + let count = Number.MAX_SAFE_INTEGER; + let selector = ''; + for ( let i = 0, n = paths.length; i < n; i++ ) { + const s = paths.slice(n - i - 1).join(''); + const elems = document.querySelectorAll(s); + if ( elems.length < count ) { + selector = s; + count = elems.length; + } } + results.push({ selector: `##${selector}`, count }); } + // Sort by most match count and shortest selector to least match count and + // longest selector. + results.sort((a, b) => { + const r = b.count - a.count; + if ( r !== 0 ) { return r; } + return a.selector.length - b.selector.length; + }); vAPI.MessagingConnection.sendTo(epickerConnectionId, { - what: 'candidateOptimized', - filter: `##${selector}`, + what: 'candidatesOptimized', + candidates: results.map(a => a.selector), + slot: details.slot, }); }; @@ -843,8 +856,7 @@ const onOptmizeCandidate = function(details) { const showDialog = function(options) { vAPI.MessagingConnection.sendTo(epickerConnectionId, { what: 'showDialog', - hostname: self.location.hostname, - origin: self.location.origin, + url: self.location.href, netFilters: netFilterCandidates, cosmeticFilters: cosmeticFilterCandidates, filter: bestCandidateFilter, @@ -1064,8 +1076,8 @@ const onDialogMessage = function(msg) { highlightElements([], true); } break; - case 'optimizeCandidate': - onOptmizeCandidate(msg); + case 'optimizeCandidates': + onOptmizeCandidates(msg); break; case 'dialogCreate': filterToDOMInterface.queryAll(msg); diff --git a/src/js/scriptlets/load-large-media-all.js b/src/js/scriptlets/load-large-media-all.js index a6d71734ae873..9d4c17f28e3ae 100644 --- a/src/js/scriptlets/load-large-media-all.js +++ b/src/js/scriptlets/load-large-media-all.js @@ -19,49 +19,23 @@ Home: https://github.com/gorhill/uBlock */ -/******************************************************************************/ - -(function() { - 'use strict'; /******************************************************************************/ -// For all media resources which have failed to load, trigger a reload. +(( ) => { -var elems, i, elem, src; - -//