@contentstorage/i18next-plugin 2.1.0-2 → 2.1.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/dist/index.esm.js CHANGED
@@ -28,12 +28,19 @@ function detectLiveEditorMode(liveEditorParam = 'contentstorage_live_editor', fo
28
28
  const win = getContentstorageWindow();
29
29
  if (!win)
30
30
  return false;
31
- // Check 1: Running in an iframe
32
- const inIframe = win.self !== win.top;
33
- // Check 2: URL has the live editor marker
34
31
  const urlParams = new URLSearchParams(win.location.search);
35
32
  const hasMarker = urlParams.has(liveEditorParam);
36
- return !!(inIframe && hasMarker);
33
+ if (!hasMarker)
34
+ return false;
35
+ // Check 1: Running in an iframe (standard live editor)
36
+ const inIframe = win.self !== win.top;
37
+ if (inIframe)
38
+ return true;
39
+ // Check 2: PiP mode (popup with opener)
40
+ const isPipMode = urlParams.get('pip_mode') === 'true' && !!win.opener;
41
+ if (isPipMode)
42
+ return true;
43
+ return false;
37
44
  }
38
45
  catch (e) {
39
46
  // Cross-origin restrictions might block window.top access
@@ -41,6 +48,32 @@ function detectLiveEditorMode(liveEditorParam = 'contentstorage_live_editor', fo
41
48
  return false;
42
49
  }
43
50
  }
51
+ /**
52
+ * Detects if the application is running in PiP (Picture-in-Picture) mode
53
+ * PiP mode requires pip_mode=true URL param and window.opener
54
+ *
55
+ * @returns true if in PiP mode
56
+ */
57
+ function detectPipMode() {
58
+ if (!isBrowser())
59
+ return false;
60
+ const win = getContentstorageWindow();
61
+ if (!win)
62
+ return false;
63
+ try {
64
+ const urlParams = new URLSearchParams(win.location.search);
65
+ if (urlParams.get('pip_mode') !== 'true')
66
+ return false;
67
+ if (!win.opener) {
68
+ console.warn('[Contentstorage] PiP mode requires opener window');
69
+ return false;
70
+ }
71
+ return true;
72
+ }
73
+ catch {
74
+ return false;
75
+ }
76
+ }
44
77
  /**
45
78
  * Initializes the global memory map if it doesn't exist
46
79
  */
@@ -58,7 +91,7 @@ function initializeMemoryMap() {
58
91
  * This script enables the click-to-edit functionality in the live editor
59
92
  */
60
93
  let liveEditorReadyPromise = null;
61
- function loadLiveEditorScript(retries = 2, delay = 3000, debug = false, customScriptUrl) {
94
+ function loadLiveEditorScript(retries = 2, delay = 3000, debug = false, customScriptUrl, mode) {
62
95
  // Return existing promise if already loading
63
96
  if (liveEditorReadyPromise) {
64
97
  return liveEditorReadyPromise;
@@ -69,17 +102,22 @@ function loadLiveEditorScript(retries = 2, delay = 3000, debug = false, customSc
69
102
  resolve(false);
70
103
  return;
71
104
  }
72
- const cdnScriptUrl = customScriptUrl || 'https://cdn.contentstorage.app/live-editor.js?contentstorage-live-editor=true';
105
+ let cdnScriptUrl = customScriptUrl || 'https://cdn.contentstorage.app/live-editor.js?contentstorage-live-editor=true';
106
+ // Add pip_mode URL parameter if in pip mode
107
+ if (mode === 'pip') {
108
+ const separator = cdnScriptUrl.includes('?') ? '&' : '?';
109
+ cdnScriptUrl += `${separator}pip_mode=true`;
110
+ }
73
111
  const loadScript = (attempt = 1) => {
74
112
  if (debug) {
75
- console.log(`[ContentStorage] Attempting to load live editor script (attempt ${attempt}/${retries})`);
113
+ console.log(`[Contentstorage] Attempting to load live editor script (attempt ${attempt}/${retries})`);
76
114
  }
77
115
  const scriptElement = win.document.createElement('script');
78
116
  scriptElement.type = 'text/javascript';
79
117
  scriptElement.src = cdnScriptUrl;
80
118
  scriptElement.onload = () => {
81
119
  if (debug) {
82
- console.log(`[ContentStorage] Live editor script loaded successfully`);
120
+ console.log(`[Contentstorage] Live editor script loaded successfully`);
83
121
  }
84
122
  resolve(true);
85
123
  };
@@ -87,13 +125,13 @@ function loadLiveEditorScript(retries = 2, delay = 3000, debug = false, customSc
87
125
  // Clean up the failed script element
88
126
  scriptElement.remove();
89
127
  if (debug) {
90
- console.error(`[ContentStorage] Failed to load live editor script (attempt ${attempt}/${retries})`, error);
128
+ console.error(`[Contentstorage] Failed to load live editor script (attempt ${attempt}/${retries})`, error);
91
129
  }
92
130
  if (attempt < retries) {
93
131
  setTimeout(() => loadScript(attempt + 1), delay);
94
132
  }
95
133
  else {
96
- console.error(`[ContentStorage] All ${retries} attempts to load live editor script failed`);
134
+ console.error(`[Contentstorage] All ${retries} attempts to load live editor script failed`);
97
135
  resolve(false);
98
136
  }
99
137
  };
@@ -110,6 +148,16 @@ function getMemoryMap() {
110
148
  const win = getContentstorageWindow();
111
149
  return (win === null || win === void 0 ? void 0 : win.memoryMap) || null;
112
150
  }
151
+ /**
152
+ * Clears all entries from the memory map
153
+ * Used by live editor to refresh tracking
154
+ */
155
+ function clearMemoryMap() {
156
+ const memoryMap = getMemoryMap();
157
+ if (memoryMap) {
158
+ memoryMap.clear();
159
+ }
160
+ }
113
161
  /**
114
162
  * Sets the current language code on the window object
115
163
  * This is used by the live editor to know which language is currently active
@@ -212,8 +260,6 @@ function extractUserVariables(options) {
212
260
  }
213
261
  return hasVariables ? variables : undefined;
214
262
  }
215
- // Schedule clear for next frame (memory map cleanup)
216
- let clearScheduled = false;
217
263
  /**
218
264
  * Tracks a translation in the memory map
219
265
  *
@@ -228,18 +274,6 @@ function trackTranslation(translationValue, translationKey, namespace, language,
228
274
  const memoryMap = getMemoryMap();
229
275
  if (!memoryMap)
230
276
  return;
231
- // Schedule clear for next frame (only once per frame)
232
- // This ensures only currently rendered translations remain in the map
233
- if (!clearScheduled && isBrowser()) {
234
- clearScheduled = true;
235
- requestAnimationFrame(() => {
236
- memoryMap.clear();
237
- clearScheduled = false;
238
- if (debug) {
239
- console.log('[ContentStorage] Memory map cleared for new frame');
240
- }
241
- });
242
- }
243
277
  // Normalize the key
244
278
  const normalizedKey = normalizeKey(translationKey);
245
279
  // Get or create entry
@@ -263,7 +297,7 @@ function trackTranslation(translationValue, translationKey, namespace, language,
263
297
  };
264
298
  memoryMap.set(translationValue, entry);
265
299
  if (debug) {
266
- console.log('[ContentStorage] Tracked translation:', {
300
+ console.log('[Contentstorage] Tracked translation:', {
267
301
  value: translationValue,
268
302
  key: normalizedKey,
269
303
  namespace,
@@ -330,10 +364,10 @@ function flattenTranslations(obj, prefix = '') {
330
364
  function debugMemoryMap() {
331
365
  const memoryMap = getMemoryMap();
332
366
  if (!memoryMap) {
333
- console.log('[ContentStorage] Memory map not initialized');
367
+ console.log('[Contentstorage] Memory map not initialized');
334
368
  return;
335
369
  }
336
- console.log('[ContentStorage] Memory map contents:');
370
+ console.log('[Contentstorage] Memory map contents:');
337
371
  console.log(`Total entries: ${memoryMap.size}`);
338
372
  const entries = Array.from(memoryMap.entries()).slice(0, 10);
339
373
  console.table(entries.map(([value, entry]) => {
@@ -377,6 +411,7 @@ class ContentstorageLiveEditorPostProcessor {
377
411
  this.type = 'postProcessor';
378
412
  this.name = 'contentstorage';
379
413
  this.isLiveMode = false;
414
+ this.i18nextInstance = null;
380
415
  this.options = {
381
416
  debug: false,
382
417
  liveEditorParam: 'contentstorage_live_editor',
@@ -393,14 +428,47 @@ class ContentstorageLiveEditorPostProcessor {
393
428
  ? navigator.language.split('-')[0]
394
429
  : 'en';
395
430
  setCurrentLanguageCode(browserLanguage);
431
+ // Detect pip mode to pass to script loading
432
+ const isPipMode = detectPipMode();
433
+ const scriptMode = isPipMode ? 'pip' : undefined;
396
434
  // Load the live editor script
397
- loadLiveEditorScript(2, 3000, this.options.debug, this.options.customLiveEditorScriptUrl);
435
+ loadLiveEditorScript(2, 3000, this.options.debug, this.options.customLiveEditorScriptUrl, scriptMode);
398
436
  if (this.options.debug) {
399
- console.log('[ContentStorage] Post-processor initialized in live mode');
400
- console.log(`[ContentStorage] Initial language code set to: ${browserLanguage}`);
437
+ console.log('[Contentstorage] Post-processor initialized in live mode');
438
+ if (isPipMode) {
439
+ console.log('[Contentstorage] PiP mode detected');
440
+ }
441
+ console.log(`[Contentstorage] Initial language code set to: ${browserLanguage}`);
401
442
  }
402
443
  }
403
444
  }
445
+ /**
446
+ * Expose refresh function on window for live-editor.js to call
447
+ * Only exposed in live mode (live editor or pip mode)
448
+ */
449
+ exposeRefreshFunction() {
450
+ if (!this.isLiveMode)
451
+ return;
452
+ const win = getContentstorageWindow();
453
+ if (!win)
454
+ return;
455
+ win.__contentstorageRefresh = () => {
456
+ var _a;
457
+ // Clear memoryMap
458
+ clearMemoryMap();
459
+ // Trigger re-render by emitting languageChanged event
460
+ // This causes useTranslation hooks to re-render
461
+ if ((_a = this.i18nextInstance) === null || _a === void 0 ? void 0 : _a.emit) {
462
+ this.i18nextInstance.emit('languageChanged', this.i18nextInstance.language);
463
+ }
464
+ if (this.options.debug) {
465
+ console.log('[Contentstorage] Refresh triggered: memoryMap cleared, languageChanged emitted');
466
+ }
467
+ };
468
+ if (this.options.debug) {
469
+ console.log('[Contentstorage] Refresh function exposed on window.__contentstorageRefresh');
470
+ }
471
+ }
404
472
  /**
405
473
  * Process the translated value
406
474
  * Called by i18next after translation resolution
@@ -411,6 +479,11 @@ class ContentstorageLiveEditorPostProcessor {
411
479
  if (!this.isLiveMode) {
412
480
  return value;
413
481
  }
482
+ // Store i18next reference on first call and expose refresh function
483
+ if (!this.i18nextInstance && translator) {
484
+ this.i18nextInstance = translator;
485
+ this.exposeRefreshFunction();
486
+ }
414
487
  // Handle array of keys (fallback keys)
415
488
  const translationKey = Array.isArray(key) ? key[0] : key;
416
489
  // Only extract namespace if key explicitly uses colon notation
@@ -520,27 +593,33 @@ class ContentstorageBackend {
520
593
  if (this.isLiveMode) {
521
594
  // Initialize memory map
522
595
  initializeMemoryMap();
596
+ // Detect pip mode to pass to script loading
597
+ const isPipMode = detectPipMode();
598
+ const scriptMode = isPipMode ? 'pip' : undefined;
523
599
  // Load the live editor script
524
- loadLiveEditorScript(2, 3000, this.options.debug, this.options.customLiveEditorScriptUrl).then((loaded) => {
600
+ loadLiveEditorScript(2, 3000, this.options.debug, this.options.customLiveEditorScriptUrl, scriptMode).then((loaded) => {
525
601
  if (loaded) {
526
602
  if (this.options.debug) {
527
- console.log('[ContentStorage] Live editor ready');
603
+ console.log('[Contentstorage] Live editor ready');
528
604
  }
529
605
  }
530
606
  else {
531
- console.warn('[ContentStorage] Failed to load live editor script');
607
+ console.warn('[Contentstorage] Failed to load live editor script');
532
608
  }
533
609
  });
534
610
  // Auto-register the post-processor for live editor tracking
535
611
  this.registerPostProcessor(services, i18nextOptions);
536
612
  if (this.options.debug) {
537
- console.log('[ContentStorage] Live editor mode enabled');
538
- console.log('[ContentStorage] Post-processor auto-registered');
539
- console.log('[ContentStorage] Plugin initialized with options:', this.options);
613
+ console.log('[Contentstorage] Live editor mode enabled');
614
+ if (isPipMode) {
615
+ console.log('[Contentstorage] PiP mode detected');
616
+ }
617
+ console.log('[Contentstorage] Post-processor auto-registered');
618
+ console.log('[Contentstorage] Plugin initialized with options:', this.options);
540
619
  }
541
620
  }
542
621
  else if (this.options.debug) {
543
- console.log('[ContentStorage] Running in normal mode (not live editor)');
622
+ console.log('[Contentstorage] Running in normal mode (not live editor)');
544
623
  }
545
624
  }
546
625
  /**
@@ -573,7 +652,7 @@ class ContentstorageBackend {
573
652
  */
574
653
  read(language, namespace, callback) {
575
654
  if (this.options.debug) {
576
- console.log(`[ContentStorage] Loading translations: ${language}/${namespace}`);
655
+ console.log(`[Contentstorage] Loading translations: ${language}/${namespace}`);
577
656
  }
578
657
  this.loadTranslations(language, namespace)
579
658
  .then((translations) => {
@@ -589,7 +668,7 @@ class ContentstorageBackend {
589
668
  })
590
669
  .catch((error) => {
591
670
  if (this.options.debug) {
592
- console.error('[ContentStorage] Failed to load translations:', error);
671
+ console.error('[Contentstorage] Failed to load translations:', error);
593
672
  }
594
673
  callback(error, false);
595
674
  });
@@ -600,7 +679,7 @@ class ContentstorageBackend {
600
679
  async loadTranslations(language, namespace) {
601
680
  const url = this.getLoadPath(language, namespace);
602
681
  if (this.options.debug) {
603
- console.log(`[ContentStorage] Fetching from: ${url}`);
682
+ console.log(`[Contentstorage] Fetching from: ${url}`);
604
683
  }
605
684
  try {
606
685
  const fetchFn = this.options.request || this.defaultFetch.bind(this);
@@ -613,7 +692,7 @@ class ContentstorageBackend {
613
692
  }
614
693
  catch (error) {
615
694
  if (this.options.debug) {
616
- console.error('[ContentStorage] Fetch error:', error);
695
+ console.error('[Contentstorage] Fetch error:', error);
617
696
  }
618
697
  throw error;
619
698
  }
@@ -645,7 +724,7 @@ class ContentstorageBackend {
645
724
  }
646
725
  // Default CDN path
647
726
  if (!contentKey) {
648
- throw new Error('[ContentStorage] contentKey is required when using default CDN path');
727
+ throw new Error('[Contentstorage] contentKey is required when using default CDN path');
649
728
  }
650
729
  // Default: Always use uppercase language code
651
730
  const lng = language.toUpperCase();
@@ -680,7 +759,7 @@ class ContentstorageBackend {
680
759
  language, this.options.debug);
681
760
  }
682
761
  if (this.options.debug) {
683
- console.log(`[ContentStorage] Tracked ${flatTranslations.length} translations for ${namespace}`);
762
+ console.log(`[Contentstorage] Tracked ${flatTranslations.length} translations for ${namespace}`);
684
763
  }
685
764
  }
686
765
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/utils.ts","../src/post-processor.ts","../src/plugin.ts"],"sourcesContent":["import type { ContentstorageWindow, MemoryMap, MemoryMapEntry } from './types';\n\n/**\n * Checks if the code is running in a browser environment\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Gets the Contentstorage window object with type safety\n */\nexport function getContentstorageWindow(): ContentstorageWindow | null {\n if (!isBrowser()) return null;\n return window as ContentstorageWindow;\n}\n\n/**\n * Detects if the application is running in ContentStorage live editor mode\n *\n * @param liveEditorParam - Query parameter name to check\n * @param forceLiveMode - Force live mode regardless of environment\n * @returns true if in live editor mode\n */\nexport function detectLiveEditorMode(\n liveEditorParam: string = 'contentstorage_live_editor',\n forceLiveMode: boolean = false\n): boolean {\n if (forceLiveMode) return true;\n if (!isBrowser()) return false;\n\n try {\n const win = getContentstorageWindow();\n if (!win) return false;\n\n // Check 1: Running in an iframe\n const inIframe = win.self !== win.top;\n\n // Check 2: URL has the live editor marker\n const urlParams = new URLSearchParams(win.location.search);\n const hasMarker = urlParams.has(liveEditorParam);\n\n return !!(inIframe && hasMarker);\n } catch (e) {\n // Cross-origin restrictions might block window.top access\n // This is expected when not in live editor mode\n return false;\n }\n}\n\n/**\n * Initializes the global memory map if it doesn't exist\n */\nexport function initializeMemoryMap(): MemoryMap | null {\n const win = getContentstorageWindow();\n if (!win) return null;\n\n if (!win.memoryMap) {\n win.memoryMap = new Map<string, MemoryMapEntry>();\n }\n\n return win.memoryMap;\n}\n\n/**\n * Load the ContentStorage live editor script\n * This script enables the click-to-edit functionality in the live editor\n */\nlet liveEditorReadyPromise: Promise<boolean> | null = null;\n\nexport function loadLiveEditorScript(\n retries: number = 2,\n delay: number = 3000,\n debug: boolean = false,\n customScriptUrl?: string\n): Promise<boolean> {\n // Return existing promise if already loading\n if (liveEditorReadyPromise) {\n return liveEditorReadyPromise;\n }\n\n liveEditorReadyPromise = new Promise<boolean>((resolve) => {\n const win = getContentstorageWindow();\n if (!win) {\n resolve(false);\n return;\n }\n\n const cdnScriptUrl = customScriptUrl || 'https://cdn.contentstorage.app/live-editor.js?contentstorage-live-editor=true';\n\n const loadScript = (attempt: number = 1) => {\n if (debug) {\n console.log(`[ContentStorage] Attempting to load live editor script (attempt ${attempt}/${retries})`);\n }\n\n const scriptElement = win.document.createElement('script');\n scriptElement.type = 'text/javascript';\n scriptElement.src = cdnScriptUrl;\n\n scriptElement.onload = () => {\n if (debug) {\n console.log(`[ContentStorage] Live editor script loaded successfully`);\n }\n resolve(true);\n };\n\n scriptElement.onerror = (error) => {\n // Clean up the failed script element\n scriptElement.remove();\n\n if (debug) {\n console.error(`[ContentStorage] Failed to load live editor script (attempt ${attempt}/${retries})`, error);\n }\n\n if (attempt < retries) {\n setTimeout(() => loadScript(attempt + 1), delay);\n } else {\n console.error(`[ContentStorage] All ${retries} attempts to load live editor script failed`);\n resolve(false);\n }\n };\n\n win.document.head.appendChild(scriptElement);\n };\n\n loadScript();\n });\n\n return liveEditorReadyPromise;\n}\n\n/**\n * Gets the global memory map\n */\nexport function getMemoryMap(): MemoryMap | null {\n const win = getContentstorageWindow();\n return win?.memoryMap || null;\n}\n\n/**\n * Sets the current language code on the window object\n * This is used by the live editor to know which language is currently active\n *\n * @param languageCode - The language code to set (e.g., 'en', 'es', 'fr')\n */\nexport function setCurrentLanguageCode(languageCode: string): void {\n const win = getContentstorageWindow();\n if (win) {\n win.currentLanguageCode = languageCode;\n }\n}\n\n/**\n * Gets the current language code from the window object\n *\n * @returns The current language code, or null if not set\n */\nexport function getCurrentLanguageCode(): string | null {\n const win = getContentstorageWindow();\n return win?.currentLanguageCode || null;\n}\n\n/**\n * Normalizes i18next key format to consistent dot notation\n * Converts namespace:key format to namespace.key\n * Only adds namespace prefix if explicitly present in the key (colon notation)\n *\n * @param key - The translation key\n * @param namespace - Optional namespace (only used if not already in key)\n * @returns Normalized key in dot notation\n */\nexport function normalizeKey(key: string, namespace?: string): string {\n // namespace parameter kept for backward compatibility but not used\n void namespace;\n\n let normalizedKey = key;\n\n // Convert colon notation to dot notation (e.g., \"common:welcome\" -> \"common.welcome\")\n if (normalizedKey.includes(':')) {\n normalizedKey = normalizedKey.replace(':', '.');\n }\n\n // Don't automatically prepend namespace - only if key already had it via colon notation\n // This ensures keys match ContentStorage content IDs by default\n\n return normalizedKey;\n}\n\n/**\n * Extracts the base translation key without interpolation context\n * Handles plural forms, contexts, and other i18next features\n *\n * Examples:\n * - 'welcome' -> 'welcome'\n * - 'items_plural' -> 'items'\n * - 'friend_male' -> 'friend'\n *\n * @param key - The translation key\n * @returns Base key without suffixes\n */\nexport function extractBaseKey(key: string): string {\n // Remove plural suffixes (_zero, _one, _two, _few, _many, _other, _plural)\n let baseKey = key.replace(/_(zero|one|two|few|many|other|plural)$/, '');\n\n // Remove context suffixes (anything after last underscore that's not a nested key)\n // Be careful not to remove underscores that are part of the actual key\n // This is a heuristic - contexts usually come at the end\n const lastUnderscore = baseKey.lastIndexOf('_');\n if (lastUnderscore > 0) {\n // Only remove if it looks like a context (short suffix, typically lowercase)\n const suffix = baseKey.substring(lastUnderscore + 1);\n if (suffix.length < 10 && suffix.toLowerCase() === suffix) {\n // This might be a context, but we'll keep it for now to avoid false positives\n // Real context handling should be done at a higher level\n }\n }\n\n return baseKey;\n}\n\n/**\n * Removes interpolation variables from a translated string\n *\n * Examples:\n * - 'Hello {{name}}!' -> 'Hello !'\n * - 'You have {{count}} items' -> 'You have items'\n *\n * @param value - The translated string\n * @returns String with interpolations removed\n */\nexport function removeInterpolation(value: string): string {\n // Remove i18next interpolation syntax: {{variable}}\n return value.replace(/\\{\\{[^}]+\\}\\}/g, '').trim();\n}\n\n/**\n * i18next internal option keys that should not be treated as user variables\n * Note: 'count' and 'context' are included as they are often used in interpolation\n */\nconst I18NEXT_INTERNAL_KEYS = new Set([\n 'defaultValue',\n 'replace',\n 'lng',\n 'lngs',\n 'fallbackLng',\n 'ns',\n 'keySeparator',\n 'nsSeparator',\n 'returnObjects',\n 'returnDetails',\n 'returnedObjectHandler',\n 'joinArrays',\n 'postProcess',\n 'interpolation',\n 'skipInterpolation',\n 'appendNamespaceToMissingKey',\n 'missingKeyHandler',\n 'parseMissingKeyHandler',\n 'overloadTranslationOptionHandler',\n 'saveMissing',\n 'saveMissingTo',\n 'missingKeyNoValueFallbackToKey',\n 'missingInterpolationHandler',\n 'formatSeparator',\n 'ignoreJSONStructure',\n]);\n\n/**\n * Extracts user-provided variables from i18next options\n * Filters out i18next internal options to return only interpolation variables\n *\n * @param options - i18next options object\n * @returns Object containing only user variables, or undefined if none\n */\nexport function extractUserVariables(options?: any): Record<string, any> | undefined {\n if (!options || typeof options !== 'object') {\n return undefined;\n }\n\n const variables: Record<string, any> = {};\n let hasVariables = false;\n\n for (const key in options) {\n if (!Object.prototype.hasOwnProperty.call(options, key)) continue;\n\n // Skip i18next internal keys\n if (I18NEXT_INTERNAL_KEYS.has(key)) continue;\n\n // Skip keys starting with underscore (private i18next properties)\n if (key.startsWith('_')) continue;\n\n // Skip undefined values\n if (options[key] === undefined) continue;\n\n // This is a user variable\n variables[key] = options[key];\n hasVariables = true;\n }\n\n return hasVariables ? variables : undefined;\n}\n\n// Schedule clear for next frame (memory map cleanup)\nlet clearScheduled = false;\n\n/**\n * Tracks a translation in the memory map\n *\n * @param translationValue - The actual translated text\n * @param translationKey - The content ID (i18next key)\n * @param namespace - Optional namespace\n * @param language - Optional language code\n * @param debug - Enable debug logging\n * @param variables - Optional interpolation variables used in the translation\n */\nexport function trackTranslation(\n translationValue: string,\n translationKey: string,\n namespace?: string,\n language?: string,\n debug: boolean = false,\n variables?: Record<string, any>\n): void {\n const memoryMap = getMemoryMap();\n if (!memoryMap) return;\n\n // Schedule clear for next frame (only once per frame)\n // This ensures only currently rendered translations remain in the map\n if (!clearScheduled && isBrowser()) {\n clearScheduled = true;\n requestAnimationFrame(() => {\n memoryMap.clear();\n clearScheduled = false;\n\n if (debug) {\n console.log('[ContentStorage] Memory map cleared for new frame');\n }\n });\n }\n\n // Normalize the key\n const normalizedKey = normalizeKey(translationKey, namespace);\n\n // Get or create entry\n const existingEntry = memoryMap.get(translationValue);\n const idSet = existingEntry ? existingEntry.ids : new Set<string>();\n idSet.add(normalizedKey);\n\n // Merge variables: prefer new variables if provided, otherwise keep existing\n // This ensures variables are preserved when backend tracks without them\n const mergedVariables = variables && Object.keys(variables).length > 0\n ? variables\n : existingEntry?.variables;\n\n const entry: MemoryMapEntry = {\n ids: idSet,\n type: 'text',\n ...(mergedVariables && Object.keys(mergedVariables).length > 0 && { variables: mergedVariables }),\n metadata: {\n namespace,\n language,\n trackedAt: Date.now(),\n },\n };\n\n memoryMap.set(translationValue, entry);\n\n if (debug) {\n console.log('[ContentStorage] Tracked translation:', {\n value: translationValue,\n key: normalizedKey,\n namespace,\n language,\n variables,\n });\n }\n}\n\n/**\n * Cleans up old entries from memory map when size exceeds limit\n * Removes oldest entries first (based on trackedAt timestamp)\n *\n * @param maxSize - Maximum number of entries to keep\n */\nexport function cleanupMemoryMap(maxSize: number): void {\n const memoryMap = getMemoryMap();\n if (!memoryMap || memoryMap.size <= maxSize) return;\n\n // Convert to array with timestamps\n const entries = Array.from(memoryMap.entries()).map(([key, value]) => ({\n key,\n value,\n timestamp: value.metadata?.trackedAt || 0,\n }));\n\n // Sort by timestamp (oldest first)\n entries.sort((a, b) => a.timestamp - b.timestamp);\n\n // Calculate how many to remove\n const toRemove = memoryMap.size - maxSize;\n\n // Remove oldest entries\n for (let i = 0; i < toRemove; i++) {\n memoryMap.delete(entries[i].key);\n }\n}\n\n/**\n * Deeply traverses a translation object and extracts all string values with their keys\n *\n * @param obj - Translation object to traverse\n * @param prefix - Current key prefix (for nested objects)\n * @returns Array of [key, value] pairs\n */\nexport function flattenTranslations(\n obj: any,\n prefix: string = ''\n): Array<[string, string]> {\n const results: Array<[string, string]> = [];\n\n for (const key in obj) {\n if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;\n\n const value = obj[key];\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n if (typeof value === 'string') {\n results.push([fullKey, value]);\n } else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n // Recurse into nested objects\n results.push(...flattenTranslations(value, fullKey));\n }\n }\n\n return results;\n}\n\n/**\n * Debug helper to log memory map contents\n */\nexport function debugMemoryMap(): void {\n const memoryMap = getMemoryMap();\n if (!memoryMap) {\n console.log('[ContentStorage] Memory map not initialized');\n return;\n }\n\n console.log('[ContentStorage] Memory map contents:');\n console.log(`Total entries: ${memoryMap.size}`);\n\n const entries = Array.from(memoryMap.entries()).slice(0, 10);\n console.table(\n entries.map(([value, entry]) => ({\n value: value.substring(0, 50),\n keys: Array.from(entry.ids).join(', '),\n namespace: entry.metadata?.namespace || 'N/A',\n }))\n );\n\n if (memoryMap.size > 10) {\n console.log(`... and ${memoryMap.size - 10} more entries`);\n }\n}\n","import type { PostProcessorModule } from 'i18next';\nimport type { ContentstoragePluginOptions } from './types';\nimport { trackTranslation, detectLiveEditorMode, initializeMemoryMap, loadLiveEditorScript, extractUserVariables, setCurrentLanguageCode } from './utils';\n\n/**\n * Contentstorage Live Editor Post-Processor\n *\n * This post-processor enables live editor functionality by tracking translations\n * at the point of resolution, capturing the actual values returned by i18next\n * including interpolations and plural forms.\n *\n * Use this to enable click-to-edit functionality in the Contentstorage live editor.\n * It works in addition to or instead of the backend plugin for more comprehensive\n * tracking, especially for dynamic translations.\n *\n * @example\n * ```typescript\n * import i18next from 'i18next';\n * import { ContentstorageLiveEditorPostProcessor } from '@contentstorage/i18next-plugin';\n *\n * i18next\n * .use(new ContentstorageLiveEditorPostProcessor({ debug: true }))\n * .init({\n * postProcess: ['contentstorage']\n * });\n * ```\n */\nexport class ContentstorageLiveEditorPostProcessor implements PostProcessorModule {\n static type: 'postProcessor' = 'postProcessor';\n type: 'postProcessor' = 'postProcessor';\n name: string = 'contentstorage';\n\n private options: ContentstoragePluginOptions;\n private isLiveMode: boolean = false;\n\n constructor(options: ContentstoragePluginOptions = {}) {\n this.options = {\n debug: false,\n liveEditorParam: 'contentstorage_live_editor',\n forceLiveMode: false,\n ...options,\n };\n\n // Detect live editor mode\n this.isLiveMode = detectLiveEditorMode(\n this.options.liveEditorParam,\n this.options.forceLiveMode\n );\n\n if (this.isLiveMode) {\n initializeMemoryMap();\n\n // Initialize current language code with browser language or fallback\n // This ensures window.currentLanguageCode is never undefined\n const browserLanguage = typeof navigator !== 'undefined' && navigator.language\n ? navigator.language.split('-')[0]\n : 'en';\n setCurrentLanguageCode(browserLanguage);\n\n // Load the live editor script\n loadLiveEditorScript(2, 3000, this.options.debug, this.options.customLiveEditorScriptUrl);\n\n if (this.options.debug) {\n console.log('[ContentStorage] Post-processor initialized in live mode');\n console.log(`[ContentStorage] Initial language code set to: ${browserLanguage}`);\n }\n }\n }\n\n /**\n * Process the translated value\n * Called by i18next after translation resolution\n */\n process(\n value: string,\n key: string | string[],\n options: any,\n translator: any\n ): string {\n // Only track in live mode\n if (!this.isLiveMode) {\n return value;\n }\n\n // Handle array of keys (fallback keys)\n const translationKey = Array.isArray(key) ? key[0] : key;\n\n // Only extract namespace if key explicitly uses colon notation\n // Don't pass namespace from options - let keys be clean by default\n let namespace: string | undefined;\n if (translationKey.includes(':')) {\n [namespace] = translationKey.split(':');\n }\n console.log('[Contentstorage plugin] ', {\n options,\n translator\n })\n // Extract language\n const language = options?.lng || translator?.language;\n\n // Set current language code for live editor\n if (language) {\n setCurrentLanguageCode(language);\n }\n\n // Extract user variables from options\n const variables = extractUserVariables(options);\n\n // Try to get the template (non-interpolated value) from the translator\n // This allows us to track the template with {{placeholders}} instead of resolved values\n let template = value;\n try {\n if (translator?.resourceStore) {\n const ns = namespace || options?.ns || translator.options?.defaultNS || 'translation';\n const lng = language || translator.language;\n\n // Try to get the raw translation template from the resource store\n const rawTranslation = translator.resourceStore.getResource(lng, ns, translationKey);\n if (rawTranslation && typeof rawTranslation === 'string') {\n template = rawTranslation;\n }\n }\n } catch (e) {\n // If we can't get the template, fall back to using the resolved value\n if (this.options.debug) {\n console.warn('[Contentstorage plugin] Could not retrieve template for:', translationKey, e);\n }\n }\n\n // Track the translation with the template\n trackTranslation(\n template,\n translationKey,\n namespace,\n language,\n this.options.debug,\n variables\n );\n\n return value;\n }\n}\n\n/**\n * Create a new instance of the Contentstorage Live Editor post-processor\n */\nexport function createContentstorageLiveEditorPostProcessor(\n options?: ContentstoragePluginOptions\n): ContentstorageLiveEditorPostProcessor {\n return new ContentstorageLiveEditorPostProcessor(options);\n}\n","import type {\n BackendModule,\n ReadCallback,\n Services,\n InitOptions,\n} from 'i18next';\nimport type {\n ContentstoragePluginOptions,\n TranslationData,\n} from './types';\nimport {\n detectLiveEditorMode,\n initializeMemoryMap,\n trackTranslation,\n cleanupMemoryMap,\n flattenTranslations,\n isBrowser,\n loadLiveEditorScript,\n} from './utils';\nimport { ContentstorageLiveEditorPostProcessor } from './post-processor';\n\n/**\n * Contentstorage i18next Backend Plugin\n *\n * This plugin enables translation tracking for the Contentstorage live editor\n * by maintaining a memory map of translations and their keys.\n *\n * Features:\n * - Automatic live editor mode detection\n * - Translation tracking with memory map\n * - Support for nested translations\n * - Memory management with size limits\n * - Custom CDN or load path support\n *\n * @example\n * ```typescript\n * import i18next from 'i18next';\n * import ContentstorageBackend from '@contentstorage/i18next-plugin';\n *\n * i18next\n * .use(ContentstorageBackend)\n * .init({\n * backend: {\n * contentKey: 'your-content-key',\n * debug: true\n * }\n * });\n * ```\n */\nexport class ContentstorageBackend implements BackendModule<ContentstoragePluginOptions> {\n static type: 'backend' = 'backend';\n type: 'backend' = 'backend';\n\n private options: ContentstoragePluginOptions;\n private isLiveMode: boolean = false;\n private postProcessor?: ContentstorageLiveEditorPostProcessor;\n\n constructor(_services?: Services, options?: ContentstoragePluginOptions, _i18nextOptions?: InitOptions) {\n this.options = options || {};\n\n // Initialize if services and i18nextOptions are provided\n // This allows i18next to initialize the plugin automatically\n if (_services && _i18nextOptions) {\n this.init(_services, options, _i18nextOptions);\n }\n }\n\n /**\n * Initialize the plugin\n * Called by i18next during initialization\n */\n init(\n services: Services,\n backendOptions: ContentstoragePluginOptions = {},\n i18nextOptions: InitOptions = {}\n ): void {\n\n this.options = {\n debug: false,\n maxMemoryMapSize: 10000,\n liveEditorParam: 'contentstorage_live_editor',\n forceLiveMode: false,\n ...backendOptions,\n };\n\n // Detect live editor mode\n this.isLiveMode = detectLiveEditorMode(\n this.options.liveEditorParam,\n this.options.forceLiveMode\n );\n\n if (this.isLiveMode) {\n // Initialize memory map\n initializeMemoryMap();\n\n // Load the live editor script\n loadLiveEditorScript(2, 3000, this.options.debug, this.options.customLiveEditorScriptUrl).then((loaded) => {\n if (loaded) {\n if (this.options.debug) {\n console.log('[ContentStorage] Live editor ready');\n }\n } else {\n console.warn('[ContentStorage] Failed to load live editor script');\n }\n });\n\n // Auto-register the post-processor for live editor tracking\n this.registerPostProcessor(services, i18nextOptions);\n\n if (this.options.debug) {\n console.log('[ContentStorage] Live editor mode enabled');\n console.log('[ContentStorage] Post-processor auto-registered');\n console.log('[ContentStorage] Plugin initialized with options:', this.options);\n }\n } else if (this.options.debug) {\n console.log('[ContentStorage] Running in normal mode (not live editor)');\n }\n }\n\n /**\n * Auto-register the live editor post-processor\n * This allows dynamic translation tracking without requiring explicit postProcess config\n */\n private registerPostProcessor(services: Services, i18nextOptions: InitOptions): void {\n // Create post-processor instance\n this.postProcessor = new ContentstorageLiveEditorPostProcessor(this.options);\n\n // Register with i18next\n services.languageUtils?.addPostProcessor(this.postProcessor);\n\n // Add to postProcess array if it exists, otherwise create it\n const initOptions = i18nextOptions as any;\n if (!initOptions.postProcess) {\n initOptions.postProcess = [];\n }\n\n // Ensure postProcess is an array\n if (!Array.isArray(initOptions.postProcess)) {\n initOptions.postProcess = [initOptions.postProcess];\n }\n\n // Add our post-processor if not already present\n if (!initOptions.postProcess.includes('contentstorage')) {\n initOptions.postProcess.push('contentstorage');\n }\n }\n\n /**\n * Read translations for a given language and namespace\n * This is the main method called by i18next to load translations\n */\n read(\n language: string,\n namespace: string,\n callback: ReadCallback\n ): void {\n if (this.options.debug) {\n console.log(`[ContentStorage] Loading translations: ${language}/${namespace}`);\n }\n\n this.loadTranslations(language, namespace)\n .then((translations) => {\n // Track translations if in live mode\n if (this.isLiveMode && this.shouldTrackNamespace(namespace)) {\n this.trackTranslations(translations, namespace, language);\n\n // Cleanup if needed\n if (this.options.maxMemoryMapSize) {\n cleanupMemoryMap(this.options.maxMemoryMapSize);\n }\n }\n\n callback(null, translations);\n })\n .catch((error) => {\n if (this.options.debug) {\n console.error('[ContentStorage] Failed to load translations:', error);\n }\n callback(error, false);\n });\n }\n\n /**\n * Load translations from CDN or custom source\n */\n private async loadTranslations(\n language: string,\n namespace: string\n ): Promise<TranslationData> {\n const url = this.getLoadPath(language, namespace);\n\n if (this.options.debug) {\n console.log(`[ContentStorage] Fetching from: ${url}`);\n }\n\n try {\n const fetchFn = this.options.request || this.defaultFetch.bind(this);\n return await fetchFn(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n },\n });\n } catch (error) {\n if (this.options.debug) {\n console.error('[ContentStorage] Fetch error:', error);\n }\n throw error;\n }\n }\n\n /**\n * Default fetch implementation\n */\n private async defaultFetch(url: string, options: RequestInit): Promise<any> {\n const response = await fetch(url, options);\n\n if (!response.ok) {\n throw new Error(\n `Failed to load translations: ${response.status} ${response.statusText}`\n );\n }\n\n return response.json();\n }\n\n /**\n * Get the URL to load translations from\n */\n private getLoadPath(language: string, namespace: string): string {\n const { loadPath, contentKey } = this.options;\n\n // Custom load path function\n if (typeof loadPath === 'function') {\n return loadPath(language, namespace);\n }\n\n // Custom load path string with interpolation\n if (typeof loadPath === 'string') {\n return loadPath\n .replace('{{lng}}', language)\n .replace('{{ns}}', namespace);\n }\n\n // Default CDN path\n if (!contentKey) {\n throw new Error(\n '[ContentStorage] contentKey is required when using default CDN path'\n );\n }\n\n // Default: Always use uppercase language code\n const lng = language.toUpperCase();\n\n // Default: https://cdn.contentstorage.app/{contentKey}/content/{LNG}.json\n return `https://cdn.contentstorage.app/${contentKey}/content/${lng}.json`;\n }\n\n /**\n * Check if a namespace should be tracked\n */\n private shouldTrackNamespace(namespace: string): boolean {\n const { trackNamespaces } = this.options;\n\n // If no filter specified, track all namespaces\n if (!trackNamespaces || trackNamespaces.length === 0) {\n return true;\n }\n\n return trackNamespaces.includes(namespace);\n }\n\n /**\n * Track all translations in the loaded data\n */\n private trackTranslations(\n translations: TranslationData,\n namespace: string,\n language: string\n ): void {\n if (!isBrowser()) return;\n\n const flatTranslations = flattenTranslations(translations);\n\n for (const [key, value] of flatTranslations) {\n // Skip empty values\n if (!value) continue;\n\n // Don't pass namespace - let keys be tracked without prefix by default\n // Only keys with explicit colon notation (e.g., \"common:welcome\") will have namespace\n trackTranslation(\n value,\n key,\n undefined, // namespace not passed by default\n language,\n this.options.debug\n );\n }\n\n if (this.options.debug) {\n console.log(\n `[ContentStorage] Tracked ${flatTranslations.length} translations for ${namespace}`\n );\n }\n }\n}\n\n/**\n * Create a new instance of the Contentstorage backend\n */\nexport function createContentstorageBackend(\n options?: ContentstoragePluginOptions\n): ContentstorageBackend {\n return new ContentstorageBackend(undefined, options);\n}\n\n// Default export\nexport default ContentstorageBackend;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.esm.js","sources":["../src/utils.ts","../src/post-processor.ts","../src/plugin.ts"],"sourcesContent":["import type { ContentstorageWindow, MemoryMap, MemoryMapEntry } from './types';\n\n/**\n * Checks if the code is running in a browser environment\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Gets the Contentstorage window object with type safety\n */\nexport function getContentstorageWindow(): ContentstorageWindow | null {\n if (!isBrowser()) return null;\n return window as ContentstorageWindow;\n}\n\n/**\n * Detects if the application is running in ContentStorage live editor mode\n *\n * @param liveEditorParam - Query parameter name to check\n * @param forceLiveMode - Force live mode regardless of environment\n * @returns true if in live editor mode\n */\nexport function detectLiveEditorMode(\n liveEditorParam: string = 'contentstorage_live_editor',\n forceLiveMode: boolean = false\n): boolean {\n if (forceLiveMode) return true;\n if (!isBrowser()) return false;\n\n try {\n const win = getContentstorageWindow();\n if (!win) return false;\n\n const urlParams = new URLSearchParams(win.location.search);\n const hasMarker = urlParams.has(liveEditorParam);\n\n if (!hasMarker) return false;\n\n // Check 1: Running in an iframe (standard live editor)\n const inIframe = win.self !== win.top;\n if (inIframe) return true;\n\n // Check 2: PiP mode (popup with opener)\n const isPipMode = urlParams.get('pip_mode') === 'true' && !!win.opener;\n if (isPipMode) return true;\n\n return false;\n } catch (e) {\n // Cross-origin restrictions might block window.top access\n // This is expected when not in live editor mode\n return false;\n }\n}\n\n/**\n * Detects if the application is running in PiP (Picture-in-Picture) mode\n * PiP mode requires pip_mode=true URL param and window.opener\n *\n * @returns true if in PiP mode\n */\nexport function detectPipMode(): boolean {\n if (!isBrowser()) return false;\n\n const win = getContentstorageWindow();\n if (!win) return false;\n\n try {\n const urlParams = new URLSearchParams(win.location.search);\n\n if (urlParams.get('pip_mode') !== 'true') return false;\n\n if (!win.opener) {\n console.warn('[Contentstorage] PiP mode requires opener window');\n return false;\n }\n\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Initializes the global memory map if it doesn't exist\n */\nexport function initializeMemoryMap(): MemoryMap | null {\n const win = getContentstorageWindow();\n if (!win) return null;\n\n if (!win.memoryMap) {\n win.memoryMap = new Map<string, MemoryMapEntry>();\n }\n\n return win.memoryMap;\n}\n\n/**\n * Load the ContentStorage live editor script\n * This script enables the click-to-edit functionality in the live editor\n */\nlet liveEditorReadyPromise: Promise<boolean> | null = null;\n\nexport function loadLiveEditorScript(\n retries: number = 2,\n delay: number = 3000,\n debug: boolean = false,\n customScriptUrl?: string,\n mode?: string\n): Promise<boolean> {\n // Return existing promise if already loading\n if (liveEditorReadyPromise) {\n return liveEditorReadyPromise;\n }\n\n liveEditorReadyPromise = new Promise<boolean>((resolve) => {\n const win = getContentstorageWindow();\n if (!win) {\n resolve(false);\n return;\n }\n\n let cdnScriptUrl = customScriptUrl || 'https://cdn.contentstorage.app/live-editor.js?contentstorage-live-editor=true';\n\n // Add pip_mode URL parameter if in pip mode\n if (mode === 'pip') {\n const separator = cdnScriptUrl.includes('?') ? '&' : '?';\n cdnScriptUrl += `${separator}pip_mode=true`;\n }\n\n const loadScript = (attempt: number = 1) => {\n if (debug) {\n console.log(`[Contentstorage] Attempting to load live editor script (attempt ${attempt}/${retries})`);\n }\n\n const scriptElement = win.document.createElement('script');\n scriptElement.type = 'text/javascript';\n scriptElement.src = cdnScriptUrl;\n\n scriptElement.onload = () => {\n if (debug) {\n console.log(`[Contentstorage] Live editor script loaded successfully`);\n }\n resolve(true);\n };\n\n scriptElement.onerror = (error) => {\n // Clean up the failed script element\n scriptElement.remove();\n\n if (debug) {\n console.error(`[Contentstorage] Failed to load live editor script (attempt ${attempt}/${retries})`, error);\n }\n\n if (attempt < retries) {\n setTimeout(() => loadScript(attempt + 1), delay);\n } else {\n console.error(`[Contentstorage] All ${retries} attempts to load live editor script failed`);\n resolve(false);\n }\n };\n\n win.document.head.appendChild(scriptElement);\n };\n\n loadScript();\n });\n\n return liveEditorReadyPromise;\n}\n\n/**\n * Gets the global memory map\n */\nexport function getMemoryMap(): MemoryMap | null {\n const win = getContentstorageWindow();\n return win?.memoryMap || null;\n}\n\n/**\n * Clears all entries from the memory map\n * Used by live editor to refresh tracking\n */\nexport function clearMemoryMap(): void {\n const memoryMap = getMemoryMap();\n if (memoryMap) {\n memoryMap.clear();\n }\n}\n\n/**\n * Sets the current language code on the window object\n * This is used by the live editor to know which language is currently active\n *\n * @param languageCode - The language code to set (e.g., 'en', 'es', 'fr')\n */\nexport function setCurrentLanguageCode(languageCode: string): void {\n const win = getContentstorageWindow();\n if (win) {\n win.currentLanguageCode = languageCode;\n }\n}\n\n/**\n * Gets the current language code from the window object\n *\n * @returns The current language code, or null if not set\n */\nexport function getCurrentLanguageCode(): string | null {\n const win = getContentstorageWindow();\n return win?.currentLanguageCode || null;\n}\n\n/**\n * Normalizes i18next key format to consistent dot notation\n * Converts namespace:key format to namespace.key\n * Only adds namespace prefix if explicitly present in the key (colon notation)\n *\n * @param key - The translation key\n * @param namespace - Optional namespace (only used if not already in key)\n * @returns Normalized key in dot notation\n */\nexport function normalizeKey(key: string, namespace?: string): string {\n // namespace parameter kept for backward compatibility but not used\n void namespace;\n\n let normalizedKey = key;\n\n // Convert colon notation to dot notation (e.g., \"common:welcome\" -> \"common.welcome\")\n if (normalizedKey.includes(':')) {\n normalizedKey = normalizedKey.replace(':', '.');\n }\n\n // Don't automatically prepend namespace - only if key already had it via colon notation\n // This ensures keys match ContentStorage content IDs by default\n\n return normalizedKey;\n}\n\n/**\n * Extracts the base translation key without interpolation context\n * Handles plural forms, contexts, and other i18next features\n *\n * Examples:\n * - 'welcome' -> 'welcome'\n * - 'items_plural' -> 'items'\n * - 'friend_male' -> 'friend'\n *\n * @param key - The translation key\n * @returns Base key without suffixes\n */\nexport function extractBaseKey(key: string): string {\n // Remove plural suffixes (_zero, _one, _two, _few, _many, _other, _plural)\n let baseKey = key.replace(/_(zero|one|two|few|many|other|plural)$/, '');\n\n // Remove context suffixes (anything after last underscore that's not a nested key)\n // Be careful not to remove underscores that are part of the actual key\n // This is a heuristic - contexts usually come at the end\n const lastUnderscore = baseKey.lastIndexOf('_');\n if (lastUnderscore > 0) {\n // Only remove if it looks like a context (short suffix, typically lowercase)\n const suffix = baseKey.substring(lastUnderscore + 1);\n if (suffix.length < 10 && suffix.toLowerCase() === suffix) {\n // This might be a context, but we'll keep it for now to avoid false positives\n // Real context handling should be done at a higher level\n }\n }\n\n return baseKey;\n}\n\n/**\n * Removes interpolation variables from a translated string\n *\n * Examples:\n * - 'Hello {{name}}!' -> 'Hello !'\n * - 'You have {{count}} items' -> 'You have items'\n *\n * @param value - The translated string\n * @returns String with interpolations removed\n */\nexport function removeInterpolation(value: string): string {\n // Remove i18next interpolation syntax: {{variable}}\n return value.replace(/\\{\\{[^}]+\\}\\}/g, '').trim();\n}\n\n/**\n * i18next internal option keys that should not be treated as user variables\n * Note: 'count' and 'context' are included as they are often used in interpolation\n */\nconst I18NEXT_INTERNAL_KEYS = new Set([\n 'defaultValue',\n 'replace',\n 'lng',\n 'lngs',\n 'fallbackLng',\n 'ns',\n 'keySeparator',\n 'nsSeparator',\n 'returnObjects',\n 'returnDetails',\n 'returnedObjectHandler',\n 'joinArrays',\n 'postProcess',\n 'interpolation',\n 'skipInterpolation',\n 'appendNamespaceToMissingKey',\n 'missingKeyHandler',\n 'parseMissingKeyHandler',\n 'overloadTranslationOptionHandler',\n 'saveMissing',\n 'saveMissingTo',\n 'missingKeyNoValueFallbackToKey',\n 'missingInterpolationHandler',\n 'formatSeparator',\n 'ignoreJSONStructure',\n]);\n\n/**\n * Extracts user-provided variables from i18next options\n * Filters out i18next internal options to return only interpolation variables\n *\n * @param options - i18next options object\n * @returns Object containing only user variables, or undefined if none\n */\nexport function extractUserVariables(options?: any): Record<string, any> | undefined {\n if (!options || typeof options !== 'object') {\n return undefined;\n }\n\n const variables: Record<string, any> = {};\n let hasVariables = false;\n\n for (const key in options) {\n if (!Object.prototype.hasOwnProperty.call(options, key)) continue;\n\n // Skip i18next internal keys\n if (I18NEXT_INTERNAL_KEYS.has(key)) continue;\n\n // Skip keys starting with underscore (private i18next properties)\n if (key.startsWith('_')) continue;\n\n // Skip undefined values\n if (options[key] === undefined) continue;\n\n // This is a user variable\n variables[key] = options[key];\n hasVariables = true;\n }\n\n return hasVariables ? variables : undefined;\n}\n\n/**\n * Tracks a translation in the memory map\n *\n * @param translationValue - The actual translated text\n * @param translationKey - The content ID (i18next key)\n * @param namespace - Optional namespace\n * @param language - Optional language code\n * @param debug - Enable debug logging\n * @param variables - Optional interpolation variables used in the translation\n */\nexport function trackTranslation(\n translationValue: string,\n translationKey: string,\n namespace?: string,\n language?: string,\n debug: boolean = false,\n variables?: Record<string, any>\n): void {\n const memoryMap = getMemoryMap();\n if (!memoryMap) return;\n\n // Normalize the key\n const normalizedKey = normalizeKey(translationKey, namespace);\n\n // Get or create entry\n const existingEntry = memoryMap.get(translationValue);\n const idSet = existingEntry ? existingEntry.ids : new Set<string>();\n idSet.add(normalizedKey);\n\n // Merge variables: prefer new variables if provided, otherwise keep existing\n // This ensures variables are preserved when backend tracks without them\n const mergedVariables = variables && Object.keys(variables).length > 0\n ? variables\n : existingEntry?.variables;\n\n const entry: MemoryMapEntry = {\n ids: idSet,\n type: 'text',\n ...(mergedVariables && Object.keys(mergedVariables).length > 0 && { variables: mergedVariables }),\n metadata: {\n namespace,\n language,\n trackedAt: Date.now(),\n },\n };\n\n memoryMap.set(translationValue, entry);\n\n if (debug) {\n console.log('[Contentstorage] Tracked translation:', {\n value: translationValue,\n key: normalizedKey,\n namespace,\n language,\n variables,\n });\n }\n}\n\n/**\n * Cleans up old entries from memory map when size exceeds limit\n * Removes oldest entries first (based on trackedAt timestamp)\n *\n * @param maxSize - Maximum number of entries to keep\n */\nexport function cleanupMemoryMap(maxSize: number): void {\n const memoryMap = getMemoryMap();\n if (!memoryMap || memoryMap.size <= maxSize) return;\n\n // Convert to array with timestamps\n const entries = Array.from(memoryMap.entries()).map(([key, value]) => ({\n key,\n value,\n timestamp: value.metadata?.trackedAt || 0,\n }));\n\n // Sort by timestamp (oldest first)\n entries.sort((a, b) => a.timestamp - b.timestamp);\n\n // Calculate how many to remove\n const toRemove = memoryMap.size - maxSize;\n\n // Remove oldest entries\n for (let i = 0; i < toRemove; i++) {\n memoryMap.delete(entries[i].key);\n }\n}\n\n/**\n * Deeply traverses a translation object and extracts all string values with their keys\n *\n * @param obj - Translation object to traverse\n * @param prefix - Current key prefix (for nested objects)\n * @returns Array of [key, value] pairs\n */\nexport function flattenTranslations(\n obj: any,\n prefix: string = ''\n): Array<[string, string]> {\n const results: Array<[string, string]> = [];\n\n for (const key in obj) {\n if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;\n\n const value = obj[key];\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n if (typeof value === 'string') {\n results.push([fullKey, value]);\n } else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n // Recurse into nested objects\n results.push(...flattenTranslations(value, fullKey));\n }\n }\n\n return results;\n}\n\n/**\n * Debug helper to log memory map contents\n */\nexport function debugMemoryMap(): void {\n const memoryMap = getMemoryMap();\n if (!memoryMap) {\n console.log('[Contentstorage] Memory map not initialized');\n return;\n }\n\n console.log('[Contentstorage] Memory map contents:');\n console.log(`Total entries: ${memoryMap.size}`);\n\n const entries = Array.from(memoryMap.entries()).slice(0, 10);\n console.table(\n entries.map(([value, entry]) => ({\n value: value.substring(0, 50),\n keys: Array.from(entry.ids).join(', '),\n namespace: entry.metadata?.namespace || 'N/A',\n }))\n );\n\n if (memoryMap.size > 10) {\n console.log(`... and ${memoryMap.size - 10} more entries`);\n }\n}\n","import type { PostProcessorModule } from 'i18next';\nimport type { ContentstoragePluginOptions } from './types';\nimport { trackTranslation, detectLiveEditorMode, detectPipMode, initializeMemoryMap, loadLiveEditorScript, extractUserVariables, setCurrentLanguageCode, clearMemoryMap, getContentstorageWindow } from './utils';\n\n/**\n * Contentstorage Live Editor Post-Processor\n *\n * This post-processor enables live editor functionality by tracking translations\n * at the point of resolution, capturing the actual values returned by i18next\n * including interpolations and plural forms.\n *\n * Use this to enable click-to-edit functionality in the Contentstorage live editor.\n * It works in addition to or instead of the backend plugin for more comprehensive\n * tracking, especially for dynamic translations.\n *\n * @example\n * ```typescript\n * import i18next from 'i18next';\n * import { ContentstorageLiveEditorPostProcessor } from '@contentstorage/i18next-plugin';\n *\n * i18next\n * .use(new ContentstorageLiveEditorPostProcessor({ debug: true }))\n * .init({\n * postProcess: ['contentstorage']\n * });\n * ```\n */\nexport class ContentstorageLiveEditorPostProcessor implements PostProcessorModule {\n static type: 'postProcessor' = 'postProcessor';\n type: 'postProcessor' = 'postProcessor';\n name: string = 'contentstorage';\n\n private options: ContentstoragePluginOptions;\n private isLiveMode: boolean = false;\n private i18nextInstance: any = null;\n\n constructor(options: ContentstoragePluginOptions = {}) {\n this.options = {\n debug: false,\n liveEditorParam: 'contentstorage_live_editor',\n forceLiveMode: false,\n ...options,\n };\n\n // Detect live editor mode\n this.isLiveMode = detectLiveEditorMode(\n this.options.liveEditorParam,\n this.options.forceLiveMode\n );\n\n if (this.isLiveMode) {\n initializeMemoryMap();\n\n // Initialize current language code with browser language or fallback\n // This ensures window.currentLanguageCode is never undefined\n const browserLanguage = typeof navigator !== 'undefined' && navigator.language\n ? navigator.language.split('-')[0]\n : 'en';\n setCurrentLanguageCode(browserLanguage);\n\n // Detect pip mode to pass to script loading\n const isPipMode = detectPipMode();\n const scriptMode = isPipMode ? 'pip' : undefined;\n\n // Load the live editor script\n loadLiveEditorScript(2, 3000, this.options.debug, this.options.customLiveEditorScriptUrl, scriptMode);\n\n if (this.options.debug) {\n console.log('[Contentstorage] Post-processor initialized in live mode');\n if (isPipMode) {\n console.log('[Contentstorage] PiP mode detected');\n }\n console.log(`[Contentstorage] Initial language code set to: ${browserLanguage}`);\n }\n }\n }\n\n /**\n * Expose refresh function on window for live-editor.js to call\n * Only exposed in live mode (live editor or pip mode)\n */\n private exposeRefreshFunction(): void {\n if (!this.isLiveMode) return;\n\n const win = getContentstorageWindow();\n if (!win) return;\n\n win.__contentstorageRefresh = () => {\n // Clear memoryMap\n clearMemoryMap();\n\n // Trigger re-render by emitting languageChanged event\n // This causes useTranslation hooks to re-render\n if (this.i18nextInstance?.emit) {\n this.i18nextInstance.emit('languageChanged', this.i18nextInstance.language);\n }\n\n if (this.options.debug) {\n console.log('[Contentstorage] Refresh triggered: memoryMap cleared, languageChanged emitted');\n }\n };\n\n if (this.options.debug) {\n console.log('[Contentstorage] Refresh function exposed on window.__contentstorageRefresh');\n }\n }\n\n /**\n * Process the translated value\n * Called by i18next after translation resolution\n */\n process(\n value: string,\n key: string | string[],\n options: any,\n translator: any\n ): string {\n // Only track in live mode\n if (!this.isLiveMode) {\n return value;\n }\n\n // Store i18next reference on first call and expose refresh function\n if (!this.i18nextInstance && translator) {\n this.i18nextInstance = translator;\n this.exposeRefreshFunction();\n }\n\n // Handle array of keys (fallback keys)\n const translationKey = Array.isArray(key) ? key[0] : key;\n\n // Only extract namespace if key explicitly uses colon notation\n // Don't pass namespace from options - let keys be clean by default\n let namespace: string | undefined;\n if (translationKey.includes(':')) {\n [namespace] = translationKey.split(':');\n }\n console.log('[Contentstorage plugin] ', {\n options,\n translator\n })\n // Extract language\n const language = options?.lng || translator?.language;\n\n // Set current language code for live editor\n if (language) {\n setCurrentLanguageCode(language);\n }\n\n // Extract user variables from options\n const variables = extractUserVariables(options);\n\n // Try to get the template (non-interpolated value) from the translator\n // This allows us to track the template with {{placeholders}} instead of resolved values\n let template = value;\n try {\n if (translator?.resourceStore) {\n const ns = namespace || options?.ns || translator.options?.defaultNS || 'translation';\n const lng = language || translator.language;\n\n // Try to get the raw translation template from the resource store\n const rawTranslation = translator.resourceStore.getResource(lng, ns, translationKey);\n if (rawTranslation && typeof rawTranslation === 'string') {\n template = rawTranslation;\n }\n }\n } catch (e) {\n // If we can't get the template, fall back to using the resolved value\n if (this.options.debug) {\n console.warn('[Contentstorage plugin] Could not retrieve template for:', translationKey, e);\n }\n }\n\n // Track the translation with the template\n trackTranslation(\n template,\n translationKey,\n namespace,\n language,\n this.options.debug,\n variables\n );\n\n return value;\n }\n}\n\n/**\n * Create a new instance of the Contentstorage Live Editor post-processor\n */\nexport function createContentstorageLiveEditorPostProcessor(\n options?: ContentstoragePluginOptions\n): ContentstorageLiveEditorPostProcessor {\n return new ContentstorageLiveEditorPostProcessor(options);\n}\n","import type {\n BackendModule,\n ReadCallback,\n Services,\n InitOptions,\n} from 'i18next';\nimport type {\n ContentstoragePluginOptions,\n TranslationData,\n} from './types';\nimport {\n detectLiveEditorMode,\n detectPipMode,\n initializeMemoryMap,\n trackTranslation,\n cleanupMemoryMap,\n flattenTranslations,\n isBrowser,\n loadLiveEditorScript,\n} from './utils';\nimport { ContentstorageLiveEditorPostProcessor } from './post-processor';\n\n/**\n * Contentstorage i18next Backend Plugin\n *\n * This plugin enables translation tracking for the Contentstorage live editor\n * by maintaining a memory map of translations and their keys.\n *\n * Features:\n * - Automatic live editor mode detection\n * - Translation tracking with memory map\n * - Support for nested translations\n * - Memory management with size limits\n * - Custom CDN or load path support\n *\n * @example\n * ```typescript\n * import i18next from 'i18next';\n * import ContentstorageBackend from '@contentstorage/i18next-plugin';\n *\n * i18next\n * .use(ContentstorageBackend)\n * .init({\n * backend: {\n * contentKey: 'your-content-key',\n * debug: true\n * }\n * });\n * ```\n */\nexport class ContentstorageBackend implements BackendModule<ContentstoragePluginOptions> {\n static type: 'backend' = 'backend';\n type: 'backend' = 'backend';\n\n private options: ContentstoragePluginOptions;\n private isLiveMode: boolean = false;\n private postProcessor?: ContentstorageLiveEditorPostProcessor;\n\n constructor(_services?: Services, options?: ContentstoragePluginOptions, _i18nextOptions?: InitOptions) {\n this.options = options || {};\n\n // Initialize if services and i18nextOptions are provided\n // This allows i18next to initialize the plugin automatically\n if (_services && _i18nextOptions) {\n this.init(_services, options, _i18nextOptions);\n }\n }\n\n /**\n * Initialize the plugin\n * Called by i18next during initialization\n */\n init(\n services: Services,\n backendOptions: ContentstoragePluginOptions = {},\n i18nextOptions: InitOptions = {}\n ): void {\n this.options = {\n debug: false,\n maxMemoryMapSize: 10000,\n liveEditorParam: 'contentstorage_live_editor',\n forceLiveMode: false,\n ...backendOptions,\n };\n\n // Detect live editor mode\n this.isLiveMode = detectLiveEditorMode(\n this.options.liveEditorParam,\n this.options.forceLiveMode\n );\n\n if (this.isLiveMode) {\n // Initialize memory map\n initializeMemoryMap();\n\n // Detect pip mode to pass to script loading\n const isPipMode = detectPipMode();\n const scriptMode = isPipMode ? 'pip' : undefined;\n\n // Load the live editor script\n loadLiveEditorScript(\n 2,\n 3000,\n this.options.debug,\n this.options.customLiveEditorScriptUrl,\n scriptMode\n ).then((loaded) => {\n if (loaded) {\n if (this.options.debug) {\n console.log('[Contentstorage] Live editor ready');\n }\n } else {\n console.warn('[Contentstorage] Failed to load live editor script');\n }\n });\n\n // Auto-register the post-processor for live editor tracking\n this.registerPostProcessor(services, i18nextOptions);\n\n if (this.options.debug) {\n console.log('[Contentstorage] Live editor mode enabled');\n if (isPipMode) {\n console.log('[Contentstorage] PiP mode detected');\n }\n console.log('[Contentstorage] Post-processor auto-registered');\n console.log('[Contentstorage] Plugin initialized with options:', this.options);\n }\n } else if (this.options.debug) {\n console.log('[Contentstorage] Running in normal mode (not live editor)');\n }\n }\n\n /**\n * Auto-register the live editor post-processor\n * This allows dynamic translation tracking without requiring explicit postProcess config\n */\n private registerPostProcessor(services: Services, i18nextOptions: InitOptions): void {\n // Create post-processor instance\n this.postProcessor = new ContentstorageLiveEditorPostProcessor(this.options);\n\n // Register with i18next\n services.languageUtils?.addPostProcessor(this.postProcessor);\n\n // Add to postProcess array if it exists, otherwise create it\n const initOptions = i18nextOptions as any;\n if (!initOptions.postProcess) {\n initOptions.postProcess = [];\n }\n\n // Ensure postProcess is an array\n if (!Array.isArray(initOptions.postProcess)) {\n initOptions.postProcess = [initOptions.postProcess];\n }\n\n // Add our post-processor if not already present\n if (!initOptions.postProcess.includes('contentstorage')) {\n initOptions.postProcess.push('contentstorage');\n }\n }\n\n /**\n * Read translations for a given language and namespace\n * This is the main method called by i18next to load translations\n */\n read(\n language: string,\n namespace: string,\n callback: ReadCallback\n ): void {\n if (this.options.debug) {\n console.log(`[Contentstorage] Loading translations: ${language}/${namespace}`);\n }\n\n this.loadTranslations(language, namespace)\n .then((translations) => {\n // Track translations if in live mode\n if (this.isLiveMode && this.shouldTrackNamespace(namespace)) {\n this.trackTranslations(translations, namespace, language);\n\n // Cleanup if needed\n if (this.options.maxMemoryMapSize) {\n cleanupMemoryMap(this.options.maxMemoryMapSize);\n }\n }\n\n callback(null, translations);\n })\n .catch((error) => {\n if (this.options.debug) {\n console.error('[Contentstorage] Failed to load translations:', error);\n }\n callback(error, false);\n });\n }\n\n /**\n * Load translations from CDN or custom source\n */\n private async loadTranslations(\n language: string,\n namespace: string\n ): Promise<TranslationData> {\n const url = this.getLoadPath(language, namespace);\n\n if (this.options.debug) {\n console.log(`[Contentstorage] Fetching from: ${url}`);\n }\n\n try {\n const fetchFn = this.options.request || this.defaultFetch.bind(this);\n return await fetchFn(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n },\n });\n } catch (error) {\n if (this.options.debug) {\n console.error('[Contentstorage] Fetch error:', error);\n }\n throw error;\n }\n }\n\n /**\n * Default fetch implementation\n */\n private async defaultFetch(url: string, options: RequestInit): Promise<any> {\n const response = await fetch(url, options);\n\n if (!response.ok) {\n throw new Error(\n `Failed to load translations: ${response.status} ${response.statusText}`\n );\n }\n\n return response.json();\n }\n\n /**\n * Get the URL to load translations from\n */\n private getLoadPath(language: string, namespace: string): string {\n const { loadPath, contentKey } = this.options;\n\n // Custom load path function\n if (typeof loadPath === 'function') {\n return loadPath(language, namespace);\n }\n\n // Custom load path string with interpolation\n if (typeof loadPath === 'string') {\n return loadPath\n .replace('{{lng}}', language)\n .replace('{{ns}}', namespace);\n }\n\n // Default CDN path\n if (!contentKey) {\n throw new Error(\n '[Contentstorage] contentKey is required when using default CDN path'\n );\n }\n\n // Default: Always use uppercase language code\n const lng = language.toUpperCase();\n\n // Default: https://cdn.contentstorage.app/{contentKey}/content/{LNG}.json\n return `https://cdn.contentstorage.app/${contentKey}/content/${lng}.json`;\n }\n\n /**\n * Check if a namespace should be tracked\n */\n private shouldTrackNamespace(namespace: string): boolean {\n const { trackNamespaces } = this.options;\n\n // If no filter specified, track all namespaces\n if (!trackNamespaces || trackNamespaces.length === 0) {\n return true;\n }\n\n return trackNamespaces.includes(namespace);\n }\n\n /**\n * Track all translations in the loaded data\n */\n private trackTranslations(\n translations: TranslationData,\n namespace: string,\n language: string\n ): void {\n if (!isBrowser()) return;\n\n const flatTranslations = flattenTranslations(translations);\n\n for (const [key, value] of flatTranslations) {\n // Skip empty values\n if (!value) continue;\n\n // Don't pass namespace - let keys be tracked without prefix by default\n // Only keys with explicit colon notation (e.g., \"common:welcome\") will have namespace\n trackTranslation(\n value,\n key,\n undefined, // namespace not passed by default\n language,\n this.options.debug\n );\n }\n\n if (this.options.debug) {\n console.log(\n `[Contentstorage] Tracked ${flatTranslations.length} translations for ${namespace}`\n );\n }\n }\n}\n\n/**\n * Create a new instance of the Contentstorage backend\n */\nexport function createContentstorageBackend(\n options?: ContentstoragePluginOptions\n): ContentstorageBackend {\n return new ContentstorageBackend(undefined, options);\n}\n\n// Default export\nexport default ContentstorageBackend;\n"],"names":[],"mappings":"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"}