@freshjuice/zest 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -0
- package/dist/zest.de.js +104 -1
- package/dist/zest.de.js.map +1 -1
- package/dist/zest.de.min.js +1 -1
- package/dist/zest.en.js +104 -1
- package/dist/zest.en.js.map +1 -1
- package/dist/zest.en.min.js +1 -1
- package/dist/zest.es.js +104 -1
- package/dist/zest.es.js.map +1 -1
- package/dist/zest.es.min.js +1 -1
- package/dist/zest.esm.js +104 -1
- package/dist/zest.esm.js.map +1 -1
- package/dist/zest.esm.min.js +1 -1
- package/dist/zest.fr.js +104 -1
- package/dist/zest.fr.js.map +1 -1
- package/dist/zest.fr.min.js +1 -1
- package/dist/zest.it.js +104 -1
- package/dist/zest.it.js.map +1 -1
- package/dist/zest.it.min.js +1 -1
- package/dist/zest.ja.js +104 -1
- package/dist/zest.ja.js.map +1 -1
- package/dist/zest.ja.min.js +1 -1
- package/dist/zest.js +104 -1
- package/dist/zest.js.map +1 -1
- package/dist/zest.min.js +1 -1
- package/dist/zest.nl.js +104 -1
- package/dist/zest.nl.js.map +1 -1
- package/dist/zest.nl.min.js +1 -1
- package/dist/zest.pl.js +104 -1
- package/dist/zest.pl.js.map +1 -1
- package/dist/zest.pl.min.js +1 -1
- package/dist/zest.pt.js +104 -1
- package/dist/zest.pt.js.map +1 -1
- package/dist/zest.pt.min.js +1 -1
- package/dist/zest.ru.js +104 -1
- package/dist/zest.ru.js.map +1 -1
- package/dist/zest.ru.min.js +1 -1
- package/dist/zest.uk.js +104 -1
- package/dist/zest.uk.js.map +1 -1
- package/dist/zest.uk.min.js +1 -1
- package/dist/zest.zh.js +104 -1
- package/dist/zest.zh.js.map +1 -1
- package/dist/zest.zh.min.js +1 -1
- package/package.json +5 -4
- package/src/api/public-api.js +97 -0
- package/src/config/defaults.js +150 -0
- package/src/config/parser.js +104 -0
- package/src/core/categories.js +52 -0
- package/src/core/cookie-interceptor.js +116 -0
- package/src/core/dnt.js +56 -0
- package/src/core/known-trackers.js +168 -0
- package/src/core/pattern-matcher.js +96 -0
- package/src/core/script-blocker.js +308 -0
- package/src/core/storage-interceptor.js +169 -0
- package/src/i18n/lang-en.js +54 -0
- package/src/i18n/single/lang-de.js +55 -0
- package/src/i18n/single/lang-en.js +55 -0
- package/src/i18n/single/lang-es.js +55 -0
- package/src/i18n/single/lang-fr.js +55 -0
- package/src/i18n/single/lang-it.js +55 -0
- package/src/i18n/single/lang-ja.js +55 -0
- package/src/i18n/single/lang-nl.js +55 -0
- package/src/i18n/single/lang-pl.js +55 -0
- package/src/i18n/single/lang-pt.js +55 -0
- package/src/i18n/single/lang-ru.js +55 -0
- package/src/i18n/single/lang-uk.js +55 -0
- package/src/i18n/single/lang-zh.js +55 -0
- package/src/i18n/translations.js +546 -0
- package/src/index.js +377 -0
- package/src/integrations/consent-signals.js +71 -0
- package/src/storage/consent-store.js +177 -0
- package/src/storage/events.js +84 -0
- package/src/ui/banner.js +130 -0
- package/src/ui/modal.js +211 -0
- package/src/ui/styles.js +498 -0
- package/src/ui/widget.js +103 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Script Blocker - Blocks and manages consent-gated scripts
|
|
3
|
+
*
|
|
4
|
+
* Modes:
|
|
5
|
+
* - manual: Only blocks scripts with data-consent-category attribute
|
|
6
|
+
* - safe: Manual + known major trackers (Google, Facebook, etc.)
|
|
7
|
+
* - strict: Safe + extended tracker list (Hotjar, Mixpanel, etc.)
|
|
8
|
+
* - doomsday: Block ALL third-party scripts
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { getCategoryForScript, isThirdParty } from './known-trackers.js';
|
|
12
|
+
|
|
13
|
+
// Queue for blocked scripts
|
|
14
|
+
const scriptQueue = [];
|
|
15
|
+
|
|
16
|
+
// MutationObserver instance
|
|
17
|
+
let observer = null;
|
|
18
|
+
|
|
19
|
+
// Current blocking mode
|
|
20
|
+
let blockingMode = 'safe';
|
|
21
|
+
|
|
22
|
+
// Custom blocked domains (user-defined)
|
|
23
|
+
let customBlockedDomains = [];
|
|
24
|
+
|
|
25
|
+
// Reference to consent checker function
|
|
26
|
+
let checkConsent = () => false;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Set the consent checker function
|
|
30
|
+
*/
|
|
31
|
+
export function setConsentChecker(fn) {
|
|
32
|
+
checkConsent = fn;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Set blocking mode
|
|
37
|
+
*/
|
|
38
|
+
export function setBlockingMode(mode) {
|
|
39
|
+
blockingMode = mode;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Set custom blocked domains
|
|
44
|
+
*/
|
|
45
|
+
export function setCustomBlockedDomains(domains) {
|
|
46
|
+
customBlockedDomains = domains || [];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Get queued scripts
|
|
51
|
+
*/
|
|
52
|
+
export function getScriptQueue() {
|
|
53
|
+
return [...scriptQueue];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Clear the script queue
|
|
58
|
+
*/
|
|
59
|
+
export function clearScriptQueue() {
|
|
60
|
+
scriptQueue.length = 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Check if script URL matches custom blocked domains
|
|
65
|
+
*/
|
|
66
|
+
function matchesCustomDomains(url) {
|
|
67
|
+
if (!url || customBlockedDomains.length === 0) return null;
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const hostname = new URL(url).hostname.toLowerCase();
|
|
71
|
+
|
|
72
|
+
for (const entry of customBlockedDomains) {
|
|
73
|
+
const domain = typeof entry === 'string' ? entry : entry.domain;
|
|
74
|
+
const category = typeof entry === 'string' ? 'marketing' : (entry.category || 'marketing');
|
|
75
|
+
|
|
76
|
+
if (hostname === domain || hostname.endsWith('.' + domain)) {
|
|
77
|
+
return category;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
} catch (e) {
|
|
81
|
+
// Invalid URL
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Determine if a script should be blocked and get its category
|
|
89
|
+
*/
|
|
90
|
+
function getScriptBlockCategory(script) {
|
|
91
|
+
// 1. Check for explicit data-consent-category attribute (always respected)
|
|
92
|
+
const explicitCategory = script.getAttribute('data-consent-category');
|
|
93
|
+
if (explicitCategory) {
|
|
94
|
+
return explicitCategory;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// 2. Skip if script has data-zest-allow attribute
|
|
98
|
+
if (script.hasAttribute('data-zest-allow')) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const src = script.src;
|
|
103
|
+
|
|
104
|
+
// No src = inline script, only block if explicitly tagged
|
|
105
|
+
if (!src) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 3. Check custom blocked domains
|
|
110
|
+
const customCategory = matchesCustomDomains(src);
|
|
111
|
+
if (customCategory) {
|
|
112
|
+
return customCategory;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 4. Mode-based blocking
|
|
116
|
+
switch (blockingMode) {
|
|
117
|
+
case 'manual':
|
|
118
|
+
// Only explicit tags, already checked above
|
|
119
|
+
return null;
|
|
120
|
+
|
|
121
|
+
case 'safe':
|
|
122
|
+
case 'strict':
|
|
123
|
+
// Check against known tracker lists
|
|
124
|
+
return getCategoryForScript(src, blockingMode);
|
|
125
|
+
|
|
126
|
+
case 'doomsday':
|
|
127
|
+
// Block all third-party scripts
|
|
128
|
+
if (isThirdParty(src)) {
|
|
129
|
+
// Try to categorize, default to marketing
|
|
130
|
+
return getCategoryForScript(src, 'strict') || 'marketing';
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
|
|
134
|
+
default:
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Block a script element
|
|
141
|
+
*/
|
|
142
|
+
function blockScript(script) {
|
|
143
|
+
// Skip already processed scripts
|
|
144
|
+
if (script.hasAttribute('data-zest-processed')) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const category = getScriptBlockCategory(script);
|
|
149
|
+
|
|
150
|
+
if (!category) {
|
|
151
|
+
script.setAttribute('data-zest-processed', 'allowed');
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (checkConsent(category)) {
|
|
156
|
+
// Consent already given - allow script
|
|
157
|
+
script.setAttribute('data-zest-processed', 'allowed');
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Store script info for later execution
|
|
162
|
+
const scriptInfo = {
|
|
163
|
+
category,
|
|
164
|
+
src: script.src,
|
|
165
|
+
inline: script.textContent,
|
|
166
|
+
type: script.type,
|
|
167
|
+
async: script.async,
|
|
168
|
+
defer: script.defer,
|
|
169
|
+
timestamp: Date.now()
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// Mark as processed
|
|
173
|
+
script.setAttribute('data-zest-processed', 'blocked');
|
|
174
|
+
script.setAttribute('data-consent-category', category);
|
|
175
|
+
|
|
176
|
+
// Disable the script
|
|
177
|
+
script.type = 'text/plain';
|
|
178
|
+
|
|
179
|
+
// If it has a src, also remove it to prevent loading
|
|
180
|
+
if (script.src) {
|
|
181
|
+
script.setAttribute('data-blocked-src', script.src);
|
|
182
|
+
script.removeAttribute('src');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
scriptQueue.push(scriptInfo);
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Execute a queued script
|
|
191
|
+
*/
|
|
192
|
+
function executeScript(scriptInfo) {
|
|
193
|
+
const script = document.createElement('script');
|
|
194
|
+
|
|
195
|
+
if (scriptInfo.src) {
|
|
196
|
+
script.src = scriptInfo.src;
|
|
197
|
+
} else if (scriptInfo.inline) {
|
|
198
|
+
script.textContent = scriptInfo.inline;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (scriptInfo.async) script.async = true;
|
|
202
|
+
if (scriptInfo.defer) script.defer = true;
|
|
203
|
+
|
|
204
|
+
script.setAttribute('data-zest-processed', 'executed');
|
|
205
|
+
script.setAttribute('data-consent-executed', 'true');
|
|
206
|
+
|
|
207
|
+
document.head.appendChild(script);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Replay queued scripts for allowed categories
|
|
212
|
+
*/
|
|
213
|
+
export function replayScripts(allowedCategories) {
|
|
214
|
+
const remaining = [];
|
|
215
|
+
|
|
216
|
+
for (const scriptInfo of scriptQueue) {
|
|
217
|
+
if (allowedCategories.includes(scriptInfo.category)) {
|
|
218
|
+
executeScript(scriptInfo);
|
|
219
|
+
} else {
|
|
220
|
+
remaining.push(scriptInfo);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
scriptQueue.length = 0;
|
|
225
|
+
scriptQueue.push(...remaining);
|
|
226
|
+
|
|
227
|
+
// Also re-enable any blocked scripts in the DOM
|
|
228
|
+
const blockedScripts = document.querySelectorAll('script[data-zest-processed="blocked"]');
|
|
229
|
+
blockedScripts.forEach(script => {
|
|
230
|
+
const category = script.getAttribute('data-consent-category');
|
|
231
|
+
if (allowedCategories.includes(category)) {
|
|
232
|
+
// Clone and replace to execute
|
|
233
|
+
const newScript = document.createElement('script');
|
|
234
|
+
|
|
235
|
+
const blockedSrc = script.getAttribute('data-blocked-src');
|
|
236
|
+
if (blockedSrc) {
|
|
237
|
+
newScript.src = blockedSrc;
|
|
238
|
+
} else {
|
|
239
|
+
newScript.textContent = script.textContent;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (script.async) newScript.async = true;
|
|
243
|
+
if (script.defer) newScript.defer = true;
|
|
244
|
+
|
|
245
|
+
newScript.setAttribute('data-zest-processed', 'executed');
|
|
246
|
+
newScript.setAttribute('data-consent-executed', 'true');
|
|
247
|
+
script.parentNode?.replaceChild(newScript, script);
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Process existing scripts in the DOM
|
|
254
|
+
*/
|
|
255
|
+
function processExistingScripts() {
|
|
256
|
+
const scripts = document.querySelectorAll('script:not([data-zest-processed])');
|
|
257
|
+
scripts.forEach(blockScript);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Handle mutations (new scripts added to DOM)
|
|
262
|
+
*/
|
|
263
|
+
function handleMutations(mutations) {
|
|
264
|
+
for (const mutation of mutations) {
|
|
265
|
+
for (const node of mutation.addedNodes) {
|
|
266
|
+
if (node.nodeName === 'SCRIPT' && !node.hasAttribute('data-zest-processed')) {
|
|
267
|
+
blockScript(node);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Check child scripts
|
|
271
|
+
if (node.querySelectorAll) {
|
|
272
|
+
const scripts = node.querySelectorAll('script:not([data-zest-processed])');
|
|
273
|
+
scripts.forEach(blockScript);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Start observing for new scripts
|
|
281
|
+
*/
|
|
282
|
+
export function startScriptBlocking(mode = 'safe', customDomains = []) {
|
|
283
|
+
blockingMode = mode;
|
|
284
|
+
customBlockedDomains = customDomains;
|
|
285
|
+
|
|
286
|
+
// Process existing scripts
|
|
287
|
+
processExistingScripts();
|
|
288
|
+
|
|
289
|
+
// Watch for new scripts
|
|
290
|
+
observer = new MutationObserver(handleMutations);
|
|
291
|
+
|
|
292
|
+
observer.observe(document.documentElement, {
|
|
293
|
+
childList: true,
|
|
294
|
+
subtree: true
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Stop observing for new scripts
|
|
302
|
+
*/
|
|
303
|
+
export function stopScriptBlocking() {
|
|
304
|
+
if (observer) {
|
|
305
|
+
observer.disconnect();
|
|
306
|
+
observer = null;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Interceptor - Intercepts localStorage and sessionStorage operations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { getCategoryForName } from './pattern-matcher.js';
|
|
6
|
+
|
|
7
|
+
// Store originals
|
|
8
|
+
let originalLocalStorage = null;
|
|
9
|
+
let originalSessionStorage = null;
|
|
10
|
+
|
|
11
|
+
// Queues for blocked operations
|
|
12
|
+
const localStorageQueue = [];
|
|
13
|
+
const sessionStorageQueue = [];
|
|
14
|
+
|
|
15
|
+
// Reference to consent checker function
|
|
16
|
+
let checkConsent = () => false;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Set the consent checker function
|
|
20
|
+
*/
|
|
21
|
+
export function setConsentChecker(fn) {
|
|
22
|
+
checkConsent = fn;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get original localStorage
|
|
27
|
+
*/
|
|
28
|
+
export function getOriginalLocalStorage() {
|
|
29
|
+
return originalLocalStorage;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get original sessionStorage
|
|
34
|
+
*/
|
|
35
|
+
export function getOriginalSessionStorage() {
|
|
36
|
+
return originalSessionStorage;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get queued localStorage operations
|
|
41
|
+
*/
|
|
42
|
+
export function getLocalStorageQueue() {
|
|
43
|
+
return [...localStorageQueue];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get queued sessionStorage operations
|
|
48
|
+
*/
|
|
49
|
+
export function getSessionStorageQueue() {
|
|
50
|
+
return [...sessionStorageQueue];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Clear storage queues
|
|
55
|
+
*/
|
|
56
|
+
export function clearStorageQueues() {
|
|
57
|
+
localStorageQueue.length = 0;
|
|
58
|
+
sessionStorageQueue.length = 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Create a proxy for storage API
|
|
63
|
+
*/
|
|
64
|
+
function createStorageProxy(storage, queue, storageName) {
|
|
65
|
+
return new Proxy(storage, {
|
|
66
|
+
get(target, prop) {
|
|
67
|
+
if (prop === 'setItem') {
|
|
68
|
+
return (key, value) => {
|
|
69
|
+
const category = getCategoryForName(key);
|
|
70
|
+
|
|
71
|
+
if (checkConsent(category)) {
|
|
72
|
+
target.setItem(key, value);
|
|
73
|
+
} else {
|
|
74
|
+
queue.push({
|
|
75
|
+
key,
|
|
76
|
+
value,
|
|
77
|
+
category,
|
|
78
|
+
timestamp: Date.now()
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Allow all other operations
|
|
85
|
+
const val = target[prop];
|
|
86
|
+
return typeof val === 'function' ? val.bind(target) : val;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Replay queued storage operations for allowed categories
|
|
93
|
+
*/
|
|
94
|
+
export function replayStorage(allowedCategories) {
|
|
95
|
+
// Replay localStorage
|
|
96
|
+
const remainingLocal = [];
|
|
97
|
+
for (const item of localStorageQueue) {
|
|
98
|
+
if (allowedCategories.includes(item.category)) {
|
|
99
|
+
originalLocalStorage?.setItem(item.key, item.value);
|
|
100
|
+
} else {
|
|
101
|
+
remainingLocal.push(item);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
localStorageQueue.length = 0;
|
|
105
|
+
localStorageQueue.push(...remainingLocal);
|
|
106
|
+
|
|
107
|
+
// Replay sessionStorage
|
|
108
|
+
const remainingSession = [];
|
|
109
|
+
for (const item of sessionStorageQueue) {
|
|
110
|
+
if (allowedCategories.includes(item.category)) {
|
|
111
|
+
originalSessionStorage?.setItem(item.key, item.value);
|
|
112
|
+
} else {
|
|
113
|
+
remainingSession.push(item);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
sessionStorageQueue.length = 0;
|
|
117
|
+
sessionStorageQueue.push(...remainingSession);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Start intercepting storage APIs
|
|
122
|
+
*/
|
|
123
|
+
export function interceptStorage() {
|
|
124
|
+
try {
|
|
125
|
+
originalLocalStorage = window.localStorage;
|
|
126
|
+
originalSessionStorage = window.sessionStorage;
|
|
127
|
+
|
|
128
|
+
Object.defineProperty(window, 'localStorage', {
|
|
129
|
+
value: createStorageProxy(originalLocalStorage, localStorageQueue, 'localStorage'),
|
|
130
|
+
configurable: true,
|
|
131
|
+
writable: false
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
Object.defineProperty(window, 'sessionStorage', {
|
|
135
|
+
value: createStorageProxy(originalSessionStorage, sessionStorageQueue, 'sessionStorage'),
|
|
136
|
+
configurable: true,
|
|
137
|
+
writable: false
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
return true;
|
|
141
|
+
} catch (e) {
|
|
142
|
+
console.warn('[Zest] Could not intercept storage APIs:', e);
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Restore original storage APIs
|
|
149
|
+
*/
|
|
150
|
+
export function restoreStorage() {
|
|
151
|
+
try {
|
|
152
|
+
if (originalLocalStorage) {
|
|
153
|
+
Object.defineProperty(window, 'localStorage', {
|
|
154
|
+
value: originalLocalStorage,
|
|
155
|
+
configurable: true,
|
|
156
|
+
writable: false
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
if (originalSessionStorage) {
|
|
160
|
+
Object.defineProperty(window, 'sessionStorage', {
|
|
161
|
+
value: originalSessionStorage,
|
|
162
|
+
configurable: true,
|
|
163
|
+
writable: false
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
} catch (e) {
|
|
167
|
+
console.warn('[Zest] Could not restore storage APIs:', e);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* English only translation
|
|
3
|
+
*/
|
|
4
|
+
export const translations = {
|
|
5
|
+
en: {
|
|
6
|
+
labels: {
|
|
7
|
+
banner: {
|
|
8
|
+
title: 'We value your privacy',
|
|
9
|
+
description: 'We use cookies to enhance your browsing experience, serve personalized content, and analyze our traffic. By clicking "Accept All", you consent to our use of cookies.',
|
|
10
|
+
acceptAll: 'Accept All',
|
|
11
|
+
rejectAll: 'Reject All',
|
|
12
|
+
settings: 'Settings'
|
|
13
|
+
},
|
|
14
|
+
modal: {
|
|
15
|
+
title: 'Privacy Settings',
|
|
16
|
+
description: 'Manage your cookie preferences. You can enable or disable different types of cookies below.',
|
|
17
|
+
save: 'Save Preferences',
|
|
18
|
+
acceptAll: 'Accept All',
|
|
19
|
+
rejectAll: 'Reject All'
|
|
20
|
+
},
|
|
21
|
+
widget: {
|
|
22
|
+
label: 'Cookie Settings'
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
categories: {
|
|
26
|
+
essential: {
|
|
27
|
+
label: 'Essential',
|
|
28
|
+
description: 'Required for the website to function properly. Cannot be disabled.'
|
|
29
|
+
},
|
|
30
|
+
functional: {
|
|
31
|
+
label: 'Functional',
|
|
32
|
+
description: 'Enable personalized features like language preferences and themes.'
|
|
33
|
+
},
|
|
34
|
+
analytics: {
|
|
35
|
+
label: 'Analytics',
|
|
36
|
+
description: 'Help us understand how visitors interact with our website.'
|
|
37
|
+
},
|
|
38
|
+
marketing: {
|
|
39
|
+
label: 'Marketing',
|
|
40
|
+
description: 'Used to deliver relevant advertisements and track campaign performance.'
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const supportedLanguages = ['en'];
|
|
47
|
+
|
|
48
|
+
export function detectLanguage() {
|
|
49
|
+
return 'en';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function getTranslation() {
|
|
53
|
+
return translations.en;
|
|
54
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DE only translation - auto-generated
|
|
3
|
+
* Do not edit manually, run: npm run build
|
|
4
|
+
*/
|
|
5
|
+
export const translations = {
|
|
6
|
+
de: {
|
|
7
|
+
"labels": {
|
|
8
|
+
"banner": {
|
|
9
|
+
"title": "Wir respektieren Ihre Privatsphäre",
|
|
10
|
+
"description": "Wir verwenden Cookies, um Ihr Surferlebnis zu verbessern, personalisierte Inhalte bereitzustellen und unseren Datenverkehr zu analysieren. Mit einem Klick auf „Alle akzeptieren\" stimmen Sie der Verwendung von Cookies zu.",
|
|
11
|
+
"acceptAll": "Alle akzeptieren",
|
|
12
|
+
"rejectAll": "Alle ablehnen",
|
|
13
|
+
"settings": "Einstellungen"
|
|
14
|
+
},
|
|
15
|
+
"modal": {
|
|
16
|
+
"title": "Datenschutzeinstellungen",
|
|
17
|
+
"description": "Verwalten Sie Ihre Cookie-Einstellungen. Sie können verschiedene Arten von Cookies unten aktivieren oder deaktivieren.",
|
|
18
|
+
"save": "Einstellungen speichern",
|
|
19
|
+
"acceptAll": "Alle akzeptieren",
|
|
20
|
+
"rejectAll": "Alle ablehnen"
|
|
21
|
+
},
|
|
22
|
+
"widget": {
|
|
23
|
+
"label": "Cookie-Einstellungen"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"categories": {
|
|
27
|
+
"essential": {
|
|
28
|
+
"label": "Notwendig",
|
|
29
|
+
"description": "Erforderlich für die ordnungsgemäße Funktion der Website. Können nicht deaktiviert werden."
|
|
30
|
+
},
|
|
31
|
+
"functional": {
|
|
32
|
+
"label": "Funktional",
|
|
33
|
+
"description": "Ermöglichen personalisierte Funktionen wie Spracheinstellungen und Designs."
|
|
34
|
+
},
|
|
35
|
+
"analytics": {
|
|
36
|
+
"label": "Analytisch",
|
|
37
|
+
"description": "Helfen uns zu verstehen, wie Besucher mit unserer Website interagieren."
|
|
38
|
+
},
|
|
39
|
+
"marketing": {
|
|
40
|
+
"label": "Marketing",
|
|
41
|
+
"description": "Werden verwendet, um relevante Werbung anzuzeigen und die Kampagnenleistung zu messen."
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const supportedLanguages = ['de'];
|
|
48
|
+
|
|
49
|
+
export function detectLanguage() {
|
|
50
|
+
return 'de';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function getTranslation() {
|
|
54
|
+
return translations.de;
|
|
55
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EN only translation - auto-generated
|
|
3
|
+
* Do not edit manually, run: npm run build
|
|
4
|
+
*/
|
|
5
|
+
export const translations = {
|
|
6
|
+
en: {
|
|
7
|
+
"labels": {
|
|
8
|
+
"banner": {
|
|
9
|
+
"title": "We value your privacy",
|
|
10
|
+
"description": "We use cookies to enhance your browsing experience, serve personalized content, and analyze our traffic. By clicking \"Accept All\", you consent to our use of cookies.",
|
|
11
|
+
"acceptAll": "Accept All",
|
|
12
|
+
"rejectAll": "Reject All",
|
|
13
|
+
"settings": "Settings"
|
|
14
|
+
},
|
|
15
|
+
"modal": {
|
|
16
|
+
"title": "Privacy Settings",
|
|
17
|
+
"description": "Manage your cookie preferences. You can enable or disable different types of cookies below.",
|
|
18
|
+
"save": "Save Preferences",
|
|
19
|
+
"acceptAll": "Accept All",
|
|
20
|
+
"rejectAll": "Reject All"
|
|
21
|
+
},
|
|
22
|
+
"widget": {
|
|
23
|
+
"label": "Cookie Settings"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"categories": {
|
|
27
|
+
"essential": {
|
|
28
|
+
"label": "Essential",
|
|
29
|
+
"description": "Required for the website to function properly. Cannot be disabled."
|
|
30
|
+
},
|
|
31
|
+
"functional": {
|
|
32
|
+
"label": "Functional",
|
|
33
|
+
"description": "Enable personalized features like language preferences and themes."
|
|
34
|
+
},
|
|
35
|
+
"analytics": {
|
|
36
|
+
"label": "Analytics",
|
|
37
|
+
"description": "Help us understand how visitors interact with our website."
|
|
38
|
+
},
|
|
39
|
+
"marketing": {
|
|
40
|
+
"label": "Marketing",
|
|
41
|
+
"description": "Used to deliver relevant advertisements and track campaign performance."
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const supportedLanguages = ['en'];
|
|
48
|
+
|
|
49
|
+
export function detectLanguage() {
|
|
50
|
+
return 'en';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function getTranslation() {
|
|
54
|
+
return translations.en;
|
|
55
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ES only translation - auto-generated
|
|
3
|
+
* Do not edit manually, run: npm run build
|
|
4
|
+
*/
|
|
5
|
+
export const translations = {
|
|
6
|
+
es: {
|
|
7
|
+
"labels": {
|
|
8
|
+
"banner": {
|
|
9
|
+
"title": "Valoramos tu privacidad",
|
|
10
|
+
"description": "Utilizamos cookies para mejorar tu experiencia de navegación, ofrecer contenido personalizado y analizar nuestro tráfico. Al hacer clic en \"Aceptar todo\", consientes el uso de cookies.",
|
|
11
|
+
"acceptAll": "Aceptar todo",
|
|
12
|
+
"rejectAll": "Rechazar todo",
|
|
13
|
+
"settings": "Configuración"
|
|
14
|
+
},
|
|
15
|
+
"modal": {
|
|
16
|
+
"title": "Configuración de privacidad",
|
|
17
|
+
"description": "Gestiona tus preferencias de cookies. Puedes activar o desactivar diferentes tipos de cookies a continuación.",
|
|
18
|
+
"save": "Guardar preferencias",
|
|
19
|
+
"acceptAll": "Aceptar todo",
|
|
20
|
+
"rejectAll": "Rechazar todo"
|
|
21
|
+
},
|
|
22
|
+
"widget": {
|
|
23
|
+
"label": "Configuración de cookies"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"categories": {
|
|
27
|
+
"essential": {
|
|
28
|
+
"label": "Esenciales",
|
|
29
|
+
"description": "Necesarias para el funcionamiento del sitio web. No se pueden desactivar."
|
|
30
|
+
},
|
|
31
|
+
"functional": {
|
|
32
|
+
"label": "Funcionales",
|
|
33
|
+
"description": "Permiten funciones personalizadas como preferencias de idioma y temas."
|
|
34
|
+
},
|
|
35
|
+
"analytics": {
|
|
36
|
+
"label": "Analíticas",
|
|
37
|
+
"description": "Nos ayudan a entender cómo los visitantes interactúan con nuestro sitio web."
|
|
38
|
+
},
|
|
39
|
+
"marketing": {
|
|
40
|
+
"label": "Marketing",
|
|
41
|
+
"description": "Se utilizan para mostrar anuncios relevantes y medir el rendimiento de las campañas."
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const supportedLanguages = ['es'];
|
|
48
|
+
|
|
49
|
+
export function detectLanguage() {
|
|
50
|
+
return 'es';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function getTranslation() {
|
|
54
|
+
return translations.es;
|
|
55
|
+
}
|