@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.
Files changed (76) hide show
  1. package/README.md +46 -0
  2. package/dist/zest.de.js +104 -1
  3. package/dist/zest.de.js.map +1 -1
  4. package/dist/zest.de.min.js +1 -1
  5. package/dist/zest.en.js +104 -1
  6. package/dist/zest.en.js.map +1 -1
  7. package/dist/zest.en.min.js +1 -1
  8. package/dist/zest.es.js +104 -1
  9. package/dist/zest.es.js.map +1 -1
  10. package/dist/zest.es.min.js +1 -1
  11. package/dist/zest.esm.js +104 -1
  12. package/dist/zest.esm.js.map +1 -1
  13. package/dist/zest.esm.min.js +1 -1
  14. package/dist/zest.fr.js +104 -1
  15. package/dist/zest.fr.js.map +1 -1
  16. package/dist/zest.fr.min.js +1 -1
  17. package/dist/zest.it.js +104 -1
  18. package/dist/zest.it.js.map +1 -1
  19. package/dist/zest.it.min.js +1 -1
  20. package/dist/zest.ja.js +104 -1
  21. package/dist/zest.ja.js.map +1 -1
  22. package/dist/zest.ja.min.js +1 -1
  23. package/dist/zest.js +104 -1
  24. package/dist/zest.js.map +1 -1
  25. package/dist/zest.min.js +1 -1
  26. package/dist/zest.nl.js +104 -1
  27. package/dist/zest.nl.js.map +1 -1
  28. package/dist/zest.nl.min.js +1 -1
  29. package/dist/zest.pl.js +104 -1
  30. package/dist/zest.pl.js.map +1 -1
  31. package/dist/zest.pl.min.js +1 -1
  32. package/dist/zest.pt.js +104 -1
  33. package/dist/zest.pt.js.map +1 -1
  34. package/dist/zest.pt.min.js +1 -1
  35. package/dist/zest.ru.js +104 -1
  36. package/dist/zest.ru.js.map +1 -1
  37. package/dist/zest.ru.min.js +1 -1
  38. package/dist/zest.uk.js +104 -1
  39. package/dist/zest.uk.js.map +1 -1
  40. package/dist/zest.uk.min.js +1 -1
  41. package/dist/zest.zh.js +104 -1
  42. package/dist/zest.zh.js.map +1 -1
  43. package/dist/zest.zh.min.js +1 -1
  44. package/package.json +5 -4
  45. package/src/api/public-api.js +97 -0
  46. package/src/config/defaults.js +150 -0
  47. package/src/config/parser.js +104 -0
  48. package/src/core/categories.js +52 -0
  49. package/src/core/cookie-interceptor.js +116 -0
  50. package/src/core/dnt.js +56 -0
  51. package/src/core/known-trackers.js +168 -0
  52. package/src/core/pattern-matcher.js +96 -0
  53. package/src/core/script-blocker.js +308 -0
  54. package/src/core/storage-interceptor.js +169 -0
  55. package/src/i18n/lang-en.js +54 -0
  56. package/src/i18n/single/lang-de.js +55 -0
  57. package/src/i18n/single/lang-en.js +55 -0
  58. package/src/i18n/single/lang-es.js +55 -0
  59. package/src/i18n/single/lang-fr.js +55 -0
  60. package/src/i18n/single/lang-it.js +55 -0
  61. package/src/i18n/single/lang-ja.js +55 -0
  62. package/src/i18n/single/lang-nl.js +55 -0
  63. package/src/i18n/single/lang-pl.js +55 -0
  64. package/src/i18n/single/lang-pt.js +55 -0
  65. package/src/i18n/single/lang-ru.js +55 -0
  66. package/src/i18n/single/lang-uk.js +55 -0
  67. package/src/i18n/single/lang-zh.js +55 -0
  68. package/src/i18n/translations.js +546 -0
  69. package/src/index.js +377 -0
  70. package/src/integrations/consent-signals.js +71 -0
  71. package/src/storage/consent-store.js +177 -0
  72. package/src/storage/events.js +84 -0
  73. package/src/ui/banner.js +130 -0
  74. package/src/ui/modal.js +211 -0
  75. package/src/ui/styles.js +498 -0
  76. 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
+ }