@lovalingo/lovalingo 0.5.29 → 0.6.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 (148) hide show
  1. package/README.md +34 -0
  2. package/dist/chunk-2FZR2AKF.mjs +88 -0
  3. package/dist/chunk-7D5LBV45.mjs +46 -0
  4. package/dist/chunk-CJOSN7RA.mjs +90 -0
  5. package/dist/chunk-VAHA2TOX.mjs +3440 -0
  6. package/dist/chunk-ZMRCSUM7.mjs +26 -0
  7. package/dist/chunk-ZVYKEEUF.mjs +220 -0
  8. package/dist/core.d.mts +131 -0
  9. package/dist/core.d.ts +131 -0
  10. package/dist/core.js +3561 -0
  11. package/dist/core.mjs +19 -0
  12. package/dist/index.d.mts +5 -0
  13. package/dist/index.d.ts +5 -25
  14. package/dist/index.js +3885 -28
  15. package/dist/index.mjs +33 -0
  16. package/dist/react-router.d.mts +101 -0
  17. package/dist/react-router.d.ts +101 -0
  18. package/dist/react-router.js +353 -0
  19. package/dist/react-router.mjs +14 -0
  20. package/dist/tanstack-router.d.mts +22 -0
  21. package/dist/tanstack-router.d.ts +22 -0
  22. package/dist/tanstack-router.js +162 -0
  23. package/dist/tanstack-router.mjs +8 -0
  24. package/package.json +34 -3
  25. package/dist/__tests__/languageFlags.test.d.ts +0 -1
  26. package/dist/__tests__/languageFlags.test.js +0 -42
  27. package/dist/__tests__/mergeEntitlements.test.d.ts +0 -1
  28. package/dist/__tests__/mergeEntitlements.test.js +0 -27
  29. package/dist/components/AixsterProvider.d.ts +0 -1
  30. package/dist/components/AixsterProvider.js +0 -1
  31. package/dist/components/LangLink.d.ts +0 -20
  32. package/dist/components/LangLink.js +0 -38
  33. package/dist/components/LangRouter.d.ts +0 -37
  34. package/dist/components/LangRouter.js +0 -191
  35. package/dist/components/LanguageSwitcher.d.ts +0 -17
  36. package/dist/components/LanguageSwitcher.js +0 -257
  37. package/dist/components/LovalingoProvider.d.ts +0 -10
  38. package/dist/components/LovalingoProvider.js +0 -413
  39. package/dist/components/NavigationOverlay.d.ts +0 -6
  40. package/dist/components/NavigationOverlay.js +0 -22
  41. package/dist/components/provider/__tests__/seoUtils.test.d.ts +0 -1
  42. package/dist/components/provider/__tests__/seoUtils.test.js +0 -13
  43. package/dist/components/provider/editModeUtils.d.ts +0 -6
  44. package/dist/components/provider/editModeUtils.js +0 -59
  45. package/dist/components/provider/localeUtils.d.ts +0 -8
  46. package/dist/components/provider/localeUtils.js +0 -46
  47. package/dist/components/provider/providerConstants.d.ts +0 -12
  48. package/dist/components/provider/providerConstants.js +0 -11
  49. package/dist/components/provider/seoUtils.d.ts +0 -8
  50. package/dist/components/provider/seoUtils.js +0 -118
  51. package/dist/components/provider/useEditModeOverlay.d.ts +0 -7
  52. package/dist/components/provider/useEditModeOverlay.js +0 -134
  53. package/dist/components/provider/useHistoryNavigationPatch.d.ts +0 -3
  54. package/dist/components/provider/useHistoryNavigationPatch.js +0 -47
  55. package/dist/components/provider/useProviderCache.d.ts +0 -12
  56. package/dist/components/provider/useProviderCache.js +0 -82
  57. package/dist/context/AixsterContext.d.ts +0 -3
  58. package/dist/context/AixsterContext.js +0 -2
  59. package/dist/context/LangContext.d.ts +0 -1
  60. package/dist/context/LangContext.js +0 -2
  61. package/dist/context/LangRoutingContext.d.ts +0 -8
  62. package/dist/context/LangRoutingContext.js +0 -7
  63. package/dist/context/LovalingoContext.d.ts +0 -1
  64. package/dist/context/LovalingoContext.js +0 -1
  65. package/dist/hooks/provider/useBundleLoading.d.ts +0 -33
  66. package/dist/hooks/provider/useBundleLoading.js +0 -380
  67. package/dist/hooks/provider/useDomRules.d.ts +0 -15
  68. package/dist/hooks/provider/useDomRules.js +0 -38
  69. package/dist/hooks/provider/useLinkAutoPrefix.d.ts +0 -12
  70. package/dist/hooks/provider/useLinkAutoPrefix.js +0 -146
  71. package/dist/hooks/provider/useNavigationPrefetch.d.ts +0 -12
  72. package/dist/hooks/provider/useNavigationPrefetch.js +0 -82
  73. package/dist/hooks/provider/usePageviewTracking.d.ts +0 -10
  74. package/dist/hooks/provider/usePageviewTracking.js +0 -44
  75. package/dist/hooks/provider/usePrehide.d.ts +0 -5
  76. package/dist/hooks/provider/usePrehide.js +0 -72
  77. package/dist/hooks/provider/useSitemapLinkTag.d.ts +0 -7
  78. package/dist/hooks/provider/useSitemapLinkTag.js +0 -28
  79. package/dist/hooks/provider/useStringMissReporting.d.ts +0 -14
  80. package/dist/hooks/provider/useStringMissReporting.js +0 -155
  81. package/dist/hooks/useAixster.d.ts +0 -6
  82. package/dist/hooks/useAixster.js +0 -14
  83. package/dist/hooks/useAixsterEdit.d.ts +0 -5
  84. package/dist/hooks/useAixsterEdit.js +0 -13
  85. package/dist/hooks/useAixsterTranslate.d.ts +0 -4
  86. package/dist/hooks/useAixsterTranslate.js +0 -12
  87. package/dist/hooks/useLang.d.ts +0 -16
  88. package/dist/hooks/useLang.js +0 -23
  89. package/dist/hooks/useLangNavigate.d.ts +0 -24
  90. package/dist/hooks/useLangNavigate.js +0 -40
  91. package/dist/hooks/useLovalingo.d.ts +0 -1
  92. package/dist/hooks/useLovalingo.js +0 -1
  93. package/dist/hooks/useLovalingoEdit.d.ts +0 -1
  94. package/dist/hooks/useLovalingoEdit.js +0 -1
  95. package/dist/hooks/useLovalingoTranslate.d.ts +0 -1
  96. package/dist/hooks/useLovalingoTranslate.js +0 -1
  97. package/dist/types.d.ts +0 -76
  98. package/dist/types.js +0 -1
  99. package/dist/utils/api.d.ts +0 -42
  100. package/dist/utils/api.js +0 -395
  101. package/dist/utils/apiTypes.d.ts +0 -78
  102. package/dist/utils/apiTypes.js +0 -1
  103. package/dist/utils/apiUtils.d.ts +0 -4
  104. package/dist/utils/apiUtils.js +0 -54
  105. package/dist/utils/domRules.d.ts +0 -2
  106. package/dist/utils/domRules.js +0 -150
  107. package/dist/utils/hash.d.ts +0 -9
  108. package/dist/utils/hash.js +0 -27
  109. package/dist/utils/languageFlags.d.ts +0 -7
  110. package/dist/utils/languageFlags.js +0 -90
  111. package/dist/utils/logger.d.ts +0 -3
  112. package/dist/utils/logger.js +0 -40
  113. package/dist/utils/markerEngine.d.ts +0 -12
  114. package/dist/utils/markerEngine.js +0 -109
  115. package/dist/utils/markerEngineApply.d.ts +0 -3
  116. package/dist/utils/markerEngineApply.js +0 -136
  117. package/dist/utils/markerEngineConstants.d.ts +0 -10
  118. package/dist/utils/markerEngineConstants.js +0 -12
  119. package/dist/utils/markerEngineCritical.d.ts +0 -2
  120. package/dist/utils/markerEngineCritical.js +0 -98
  121. package/dist/utils/markerEngineDomUtils.d.ts +0 -8
  122. package/dist/utils/markerEngineDomUtils.js +0 -74
  123. package/dist/utils/markerEngineFilters.d.ts +0 -2
  124. package/dist/utils/markerEngineFilters.js +0 -26
  125. package/dist/utils/markerEngineMisses.d.ts +0 -5
  126. package/dist/utils/markerEngineMisses.js +0 -81
  127. package/dist/utils/markerEngineOriginals.d.ts +0 -5
  128. package/dist/utils/markerEngineOriginals.js +0 -29
  129. package/dist/utils/markerEngineScan.d.ts +0 -5
  130. package/dist/utils/markerEngineScan.js +0 -162
  131. package/dist/utils/markerEngineState.d.ts +0 -4
  132. package/dist/utils/markerEngineState.js +0 -14
  133. package/dist/utils/markerEngineStats.d.ts +0 -3
  134. package/dist/utils/markerEngineStats.js +0 -28
  135. package/dist/utils/markerEngineTranslations.d.ts +0 -3
  136. package/dist/utils/markerEngineTranslations.js +0 -49
  137. package/dist/utils/markerEngineTypes.d.ts +0 -62
  138. package/dist/utils/markerEngineTypes.js +0 -1
  139. package/dist/utils/markerEngineViewport.d.ts +0 -2
  140. package/dist/utils/markerEngineViewport.js +0 -27
  141. package/dist/utils/mergeEntitlements.d.ts +0 -2
  142. package/dist/utils/mergeEntitlements.js +0 -7
  143. package/dist/utils/nonLocalizedPaths.d.ts +0 -12
  144. package/dist/utils/nonLocalizedPaths.js +0 -136
  145. package/dist/utils/pathNormalizer.d.ts +0 -49
  146. package/dist/utils/pathNormalizer.js +0 -115
  147. package/dist/version.d.ts +0 -1
  148. package/dist/version.js +0 -1
@@ -1,150 +0,0 @@
1
- const DEFAULT_MATCH_SELECTOR = 'button,a,label,summary,[role="button"],[role="link"],[role="tab"]';
2
- function ensureStyleTag(id, css) {
3
- const existing = document.querySelector(`style[data-lovalingo-rule="${id}"]`);
4
- if (existing)
5
- return;
6
- const style = document.createElement('style');
7
- style.setAttribute('data-lovalingo-rule', id);
8
- style.textContent = css;
9
- document.head.appendChild(style);
10
- }
11
- function ensureScriptTag(id, script) {
12
- const existing = document.querySelector(`script[data-lovalingo-rule="${id}"]`);
13
- if (existing)
14
- return;
15
- const el = document.createElement('script');
16
- el.setAttribute('data-lovalingo-rule', id);
17
- el.textContent = script;
18
- document.head.appendChild(el);
19
- }
20
- function shouldSkipElement(el, ruleId) {
21
- return el.hasAttribute(`data-lovalingo-rule-${ruleId}`);
22
- }
23
- function markElement(el, ruleId) {
24
- el.setAttribute(`data-lovalingo-rule-${ruleId}`, '1');
25
- }
26
- function collectElements(rule, matchText) {
27
- if (rule.selector)
28
- return Array.from(document.querySelectorAll(rule.selector));
29
- if (matchText)
30
- return Array.from(document.querySelectorAll(DEFAULT_MATCH_SELECTOR));
31
- return [];
32
- }
33
- export function applyDomRules(rules) {
34
- if (!Array.isArray(rules) || rules.length === 0)
35
- return 0;
36
- let applied = 0;
37
- for (const rule of rules) {
38
- if (!rule || !rule.id)
39
- continue;
40
- const payload = rule.payload || {};
41
- const matchText = payload.matchText?.trim() || null;
42
- switch (rule.rule_type) {
43
- case 'css': {
44
- const css = payload.css || '';
45
- if (css.trim().length > 0) {
46
- ensureStyleTag(rule.id, css);
47
- applied += 1;
48
- }
49
- break;
50
- }
51
- case 'script': {
52
- const script = payload.script || '';
53
- if (script.trim().length > 0) {
54
- ensureScriptTag(rule.id, script);
55
- applied += 1;
56
- }
57
- break;
58
- }
59
- case 'remove': {
60
- const elements = collectElements(rule, matchText);
61
- for (const el of elements) {
62
- if (shouldSkipElement(el, rule.id))
63
- continue;
64
- el.remove();
65
- applied += 1;
66
- }
67
- break;
68
- }
69
- case 'add_class': {
70
- const className = payload.className || payload.value || '';
71
- if (!className.trim())
72
- break;
73
- const elements = collectElements(rule, matchText);
74
- for (const el of elements) {
75
- if (shouldSkipElement(el, rule.id))
76
- continue;
77
- if (matchText) {
78
- const current = (el.textContent || '').trim();
79
- if (current !== matchText)
80
- continue;
81
- }
82
- className.split(/\s+/).forEach((cls) => cls && el.classList.add(cls));
83
- markElement(el, rule.id);
84
- applied += 1;
85
- }
86
- break;
87
- }
88
- case 'set_attribute': {
89
- const attribute = payload.attribute || '';
90
- const value = payload.value || payload.text || '';
91
- if (!attribute || !value)
92
- break;
93
- const elements = collectElements(rule, matchText);
94
- for (const el of elements) {
95
- if (shouldSkipElement(el, rule.id))
96
- continue;
97
- if (matchText) {
98
- const current = (el.textContent || '').trim();
99
- if (current !== matchText)
100
- continue;
101
- }
102
- el.setAttribute(attribute, value);
103
- markElement(el, rule.id);
104
- applied += 1;
105
- }
106
- break;
107
- }
108
- case 'set_html': {
109
- const html = payload.html || '';
110
- if (!html)
111
- break;
112
- const elements = collectElements(rule, matchText);
113
- for (const el of elements) {
114
- if (shouldSkipElement(el, rule.id))
115
- continue;
116
- if (matchText) {
117
- const current = (el.textContent || '').trim();
118
- if (current !== matchText)
119
- continue;
120
- }
121
- el.innerHTML = html;
122
- markElement(el, rule.id);
123
- applied += 1;
124
- }
125
- break;
126
- }
127
- case 'replace_text':
128
- default: {
129
- const replacement = payload.text || payload.value || '';
130
- if (!replacement)
131
- break;
132
- const elements = collectElements(rule, matchText);
133
- for (const el of elements) {
134
- if (shouldSkipElement(el, rule.id))
135
- continue;
136
- if (matchText) {
137
- const current = (el.textContent || '').trim();
138
- if (current !== matchText)
139
- continue;
140
- }
141
- el.textContent = replacement;
142
- markElement(el, rule.id);
143
- applied += 1;
144
- }
145
- break;
146
- }
147
- }
148
- }
149
- return applied;
150
- }
@@ -1,9 +0,0 @@
1
- /**
2
- * Simple, fast hash function for content addressing
3
- * Uses djb2 algorithm - good distribution, very fast
4
- */
5
- export declare function hashContent(text: string): string;
6
- /**
7
- * Hash with context (includes placeholders info for uniqueness)
8
- */
9
- export declare function hashWithContext(text: string, placeholders?: Map<string, string>): string;
@@ -1,27 +0,0 @@
1
- /**
2
- * Simple, fast hash function for content addressing
3
- * Uses djb2 algorithm - good distribution, very fast
4
- */
5
- export function hashContent(text) {
6
- if (!text || text.length === 0) {
7
- return '0';
8
- }
9
- let hash = 5381;
10
- for (let i = 0; i < text.length; i++) {
11
- hash = ((hash << 5) + hash) + text.charCodeAt(i); // hash * 33 + c
12
- }
13
- // Convert to positive base36 string (compact representation)
14
- return Math.abs(hash).toString(36);
15
- }
16
- /**
17
- * Hash with context (includes placeholders info for uniqueness)
18
- */
19
- export function hashWithContext(text, placeholders) {
20
- const baseHash = hashContent(text);
21
- if (!placeholders || placeholders.size === 0) {
22
- return baseHash;
23
- }
24
- // Include placeholder keys in hash for uniqueness
25
- const placeholderKeys = Array.from(placeholders.keys()).sort().join(',');
26
- return hashContent(`${text}:${placeholderKeys}`);
27
- }
@@ -1,7 +0,0 @@
1
- export declare function normalizeLocaleCode(locale: unknown): string;
2
- export declare function parseLocale(locale: unknown): {
3
- language: string;
4
- region: string | null;
5
- };
6
- export declare function countryCodeToFlagEmoji(countryCode: unknown): string | null;
7
- export declare function resolveLocaleFlag(locale: unknown): string;
@@ -1,90 +0,0 @@
1
- const EXACT_LOCALE_FLAG_OVERRIDES = {
2
- en: "🇬🇧",
3
- ar: "🇸🇦",
4
- zh: "🇨🇳",
5
- fa: "🇮🇷",
6
- he: "🇮🇱",
7
- };
8
- const LANGUAGE_DEFAULT_REGION = {
9
- ar: "SA",
10
- bn: "BD",
11
- cs: "CZ",
12
- da: "DK",
13
- de: "DE",
14
- el: "GR",
15
- en: "GB",
16
- es: "ES",
17
- fa: "IR",
18
- fi: "FI",
19
- fr: "FR",
20
- he: "IL",
21
- hi: "IN",
22
- hu: "HU",
23
- hy: "AM",
24
- id: "ID",
25
- it: "IT",
26
- ja: "JP",
27
- ko: "KR",
28
- nl: "NL",
29
- no: "NO",
30
- pl: "PL",
31
- pt: "PT",
32
- ro: "RO",
33
- ru: "RU",
34
- sk: "SK",
35
- sv: "SE",
36
- th: "TH",
37
- tr: "TR",
38
- uk: "UA",
39
- vi: "VN",
40
- yo: "NG",
41
- zh: "CN",
42
- };
43
- export function normalizeLocaleCode(locale) {
44
- if (typeof locale !== "string")
45
- return "";
46
- return locale.trim().replace(/_/g, "-").toLowerCase();
47
- }
48
- export function parseLocale(locale) {
49
- const normalized = normalizeLocaleCode(locale);
50
- if (!normalized)
51
- return { language: "", region: null };
52
- const parts = normalized.split("-").filter(Boolean);
53
- const language = parts[0] || "";
54
- const regionPart = parts.find((part, index) => index > 0 && /^[a-z]{2}$/.test(part));
55
- const region = regionPart ? regionPart.toUpperCase() : null;
56
- return { language, region };
57
- }
58
- export function countryCodeToFlagEmoji(countryCode) {
59
- if (typeof countryCode !== "string")
60
- return null;
61
- const normalized = countryCode.trim().toUpperCase();
62
- if (!/^[A-Z]{2}$/.test(normalized))
63
- return null;
64
- const first = normalized.charCodeAt(0) + 127397;
65
- const second = normalized.charCodeAt(1) + 127397;
66
- return String.fromCodePoint(first, second);
67
- }
68
- export function resolveLocaleFlag(locale) {
69
- const normalized = normalizeLocaleCode(locale);
70
- if (!normalized)
71
- return "🌐";
72
- const exact = EXACT_LOCALE_FLAG_OVERRIDES[normalized];
73
- if (exact)
74
- return exact;
75
- const { language, region } = parseLocale(normalized);
76
- if (!language)
77
- return "🌐";
78
- if (region) {
79
- const regionFlag = countryCodeToFlagEmoji(region);
80
- if (regionFlag)
81
- return regionFlag;
82
- }
83
- const defaultRegion = LANGUAGE_DEFAULT_REGION[language];
84
- if (defaultRegion) {
85
- const defaultFlag = countryCodeToFlagEmoji(defaultRegion);
86
- if (defaultFlag)
87
- return defaultFlag;
88
- }
89
- return "🌐";
90
- }
@@ -1,3 +0,0 @@
1
- export declare function logDebug(...args: unknown[]): void;
2
- export declare function warnDebug(...args: unknown[]): void;
3
- export declare function errorDebug(...args: unknown[]): void;
@@ -1,40 +0,0 @@
1
- function isDebugEnabled() {
2
- if (typeof globalThis === "undefined")
3
- return false;
4
- const value = globalThis.__lovalingoDebug;
5
- if (value === true || value === "true" || value === 1)
6
- return true;
7
- try {
8
- const params = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : null;
9
- const query = params?.get("lovalingoDebug") || params?.get("lovalingo_debug") || "";
10
- if (query === "1" || query === "true")
11
- return true;
12
- }
13
- catch {
14
- // ignore
15
- }
16
- try {
17
- const stored = typeof window !== "undefined" ? window.localStorage?.getItem("Lovalingo_debug") : null;
18
- if (stored === "1" || stored === "true")
19
- return true;
20
- }
21
- catch {
22
- // ignore
23
- }
24
- return false;
25
- }
26
- export function logDebug(...args) {
27
- if (!isDebugEnabled())
28
- return;
29
- console.log(...args);
30
- }
31
- export function warnDebug(...args) {
32
- if (!isDebugEnabled())
33
- return;
34
- console.warn(...args);
35
- }
36
- export function errorDebug(...args) {
37
- if (!isDebugEnabled())
38
- return;
39
- console.error(...args);
40
- }
@@ -1,12 +0,0 @@
1
- import type { Exclusion } from "../types";
2
- import type { MarkerEngineOptions, MarkerStats } from "./markerEngineTypes";
3
- import { applyActiveTranslations, restoreDom } from "./markerEngineApply";
4
- import { getCriticalFingerprint } from "./markerEngineCritical";
5
- import { scanDomForMisses } from "./markerEngineMisses";
6
- import { addActiveTranslations, setActiveTranslations } from "./markerEngineTranslations";
7
- export declare function startMarkerEngine(options?: MarkerEngineOptions): typeof stopMarkerEngine;
8
- export declare function stopMarkerEngine(): void;
9
- export declare function getMarkerStats(): MarkerStats;
10
- export declare function setMarkerEngineExclusions(exclusions: Exclusion[] | null): void;
11
- export { applyActiveTranslations, scanDomForMisses, restoreDom, setActiveTranslations, addActiveTranslations, getCriticalFingerprint };
12
- export type { MarkerStats, MarkerEngineOptions, DomScanOccurrence, DomScanSegment, DomScanResult, DomMiss, DomMissScanResult, CriticalFingerprint, } from "./markerEngineTypes";
@@ -1,109 +0,0 @@
1
- import { DEFAULT_THROTTLE_MS } from "./markerEngineConstants";
2
- import { applyActiveTranslations, applyTranslationMap, restoreDom } from "./markerEngineApply";
3
- import { getCriticalFingerprint } from "./markerEngineCritical";
4
- import { scanDom } from "./markerEngineScan";
5
- import { scanDomForMisses } from "./markerEngineMisses";
6
- import { addActiveTranslations, setActiveTranslations } from "./markerEngineTranslations";
7
- import { buildEmptyStats } from "./markerEngineStats";
8
- import { getActiveTranslationMap, setCustomExcludeSelector } from "./markerEngineState";
9
- let observer = null;
10
- let scheduled = null;
11
- let running = false;
12
- let lastStats = buildEmptyStats();
13
- let throttleMs = DEFAULT_THROTTLE_MS;
14
- let applying = false;
15
- function scanDomWithGlobals(opts) {
16
- const result = scanDom(opts);
17
- setGlobalStats(result.stats);
18
- return result;
19
- }
20
- function setGlobalStats(stats) {
21
- lastStats = stats;
22
- if (typeof window === "undefined")
23
- return;
24
- window.__lovalingoMarkersReady = true;
25
- window.__lovalingoMarkerStats = stats;
26
- const g = window;
27
- if (!g.__lovalingo)
28
- g.__lovalingo = {};
29
- if (!g.__lovalingo.dom)
30
- g.__lovalingo.dom = {};
31
- g.__lovalingo.dom.getStats = () => lastStats;
32
- g.__lovalingo.dom.scan = () => scanDomWithGlobals({ maxSegments: 20000, includeCritical: true });
33
- g.__lovalingo.dom.getCriticalFingerprint = () => getCriticalFingerprint();
34
- g.__lovalingo.dom.apply = (bundle) => ({ applied: applyTranslationMap(bundle, document.body) });
35
- g.__lovalingo.dom.restore = () => restoreDom(document.body);
36
- }
37
- function scheduleScan() {
38
- if (!running)
39
- return;
40
- if (scheduled != null)
41
- return;
42
- scheduled = window.setTimeout(() => {
43
- scheduled = null;
44
- try {
45
- scanDomWithGlobals({ maxSegments: 20000 });
46
- if (getActiveTranslationMap()) {
47
- applying = true;
48
- applyActiveTranslations(document.body);
49
- }
50
- }
51
- finally {
52
- applying = false;
53
- }
54
- }, throttleMs);
55
- }
56
- export function startMarkerEngine(options = {}) {
57
- if (typeof window === "undefined" || typeof document === "undefined") {
58
- return () => undefined;
59
- }
60
- stopMarkerEngine();
61
- running = true;
62
- throttleMs = Math.max(20, options.throttleMs ?? DEFAULT_THROTTLE_MS);
63
- const startObserver = () => {
64
- if (!running)
65
- return;
66
- if (!document.body) {
67
- window.setTimeout(startObserver, 50);
68
- return;
69
- }
70
- observer = new MutationObserver(() => {
71
- if (applying)
72
- return;
73
- scheduleScan();
74
- });
75
- observer.observe(document.body, {
76
- childList: true,
77
- subtree: true,
78
- characterData: true,
79
- });
80
- scanDomWithGlobals({ maxSegments: 20000 });
81
- };
82
- startObserver();
83
- return stopMarkerEngine;
84
- }
85
- export function stopMarkerEngine() {
86
- running = false;
87
- if (scheduled != null) {
88
- window.clearTimeout(scheduled);
89
- scheduled = null;
90
- }
91
- if (observer) {
92
- observer.disconnect();
93
- observer = null;
94
- }
95
- }
96
- export function getMarkerStats() {
97
- return lastStats;
98
- }
99
- export function setMarkerEngineExclusions(exclusions) {
100
- if (!exclusions || exclusions.length === 0) {
101
- setCustomExcludeSelector(null);
102
- return;
103
- }
104
- const selectors = exclusions
105
- .filter((e) => e && e.type === "css" && typeof e.selector === "string" && e.selector.trim())
106
- .map((e) => e.selector.trim());
107
- setCustomExcludeSelector(selectors.length ? selectors.join(",") : null);
108
- }
109
- export { applyActiveTranslations, scanDomForMisses, restoreDom, setActiveTranslations, addActiveTranslations, getCriticalFingerprint };
@@ -1,3 +0,0 @@
1
- export declare function applyTranslationMap(bundle: Record<string, string>, root: ParentNode | null): number;
2
- export declare function applyActiveTranslations(root?: ParentNode | null): number;
3
- export declare function restoreDom(root?: ParentNode | null): void;
@@ -1,136 +0,0 @@
1
- import { ATTRIBUTE_MARKS } from "./markerEngineConstants";
2
- import { findUnsafeContainer, isExcludedElement } from "./markerEngineFilters";
3
- import { isTranslatableText, normalizeWhitespace } from "./markerEngineDomUtils";
4
- import { getOrInitAttrOriginal, getOrInitTextOriginal, originalAttrByEl, originalTextByNode } from "./markerEngineOriginals";
5
- import { getActiveTranslationMap, setActiveTranslationMap } from "./markerEngineState";
6
- export function applyTranslationMap(bundle, root) {
7
- if (!root)
8
- return 0;
9
- const map = new Map();
10
- for (const [k, v] of Object.entries(bundle || {})) {
11
- const source = normalizeWhitespace((k || "").toString());
12
- const translated = (v ?? "").toString();
13
- if (!source || !translated)
14
- continue;
15
- map.set(source, translated);
16
- }
17
- setActiveTranslationMap(map);
18
- return applyActiveTranslations(root);
19
- }
20
- export function applyActiveTranslations(root = document.body) {
21
- const map = getActiveTranslationMap();
22
- if (!root || !map || map.size === 0)
23
- return 0;
24
- let applied = 0;
25
- const walk = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
26
- const nodes = [];
27
- let node = walk.nextNode();
28
- while (node) {
29
- if (node.nodeType === Node.TEXT_NODE)
30
- nodes.push(node);
31
- node = walk.nextNode();
32
- }
33
- for (const textNode of nodes) {
34
- const parent = textNode.parentElement;
35
- if (!parent)
36
- continue;
37
- const raw = textNode.nodeValue || "";
38
- const trimmed = raw.trim();
39
- if (!trimmed)
40
- continue;
41
- if (isExcludedElement(parent))
42
- continue;
43
- if (findUnsafeContainer(parent))
44
- continue;
45
- if (!isTranslatableText(trimmed))
46
- continue;
47
- const original = getOrInitTextOriginal(textNode, parent);
48
- const key = normalizeWhitespace(original.trimmed);
49
- const translation = map.get(key);
50
- if (!translation)
51
- continue;
52
- const next = `${original.leading}${translation}${original.trailing}`;
53
- if (textNode.nodeValue === next)
54
- continue;
55
- try {
56
- textNode.nodeValue = next;
57
- applied += 1;
58
- }
59
- catch {
60
- // ignore
61
- }
62
- }
63
- if (root instanceof HTMLElement) {
64
- const elements = root.querySelectorAll("[title],[aria-label],[placeholder]");
65
- elements.forEach((el) => {
66
- if (isExcludedElement(el))
67
- return;
68
- if (findUnsafeContainer(el))
69
- return;
70
- for (const { attr } of ATTRIBUTE_MARKS) {
71
- const current = el.getAttribute(attr);
72
- if (!current)
73
- continue;
74
- const trimmed = current.trim();
75
- if (!trimmed || !isTranslatableText(trimmed))
76
- continue;
77
- const original = normalizeWhitespace(getOrInitAttrOriginal(el, attr));
78
- const translation = map.get(original);
79
- if (!translation)
80
- continue;
81
- if (el.getAttribute(attr) === translation)
82
- continue;
83
- try {
84
- el.setAttribute(attr, translation);
85
- applied += 1;
86
- }
87
- catch {
88
- // ignore
89
- }
90
- }
91
- });
92
- }
93
- return applied;
94
- }
95
- export function restoreDom(root = document.body) {
96
- if (!root)
97
- return;
98
- const walk = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
99
- let node = walk.nextNode();
100
- while (node) {
101
- if (node.nodeType === Node.TEXT_NODE) {
102
- const textNode = node;
103
- const original = originalTextByNode.get(textNode);
104
- if (original && textNode.nodeValue !== original.raw) {
105
- try {
106
- textNode.nodeValue = original.raw;
107
- }
108
- catch {
109
- // ignore
110
- }
111
- }
112
- }
113
- node = walk.nextNode();
114
- }
115
- if (root instanceof HTMLElement) {
116
- const elements = root.querySelectorAll("[title],[aria-label],[placeholder]");
117
- elements.forEach((el) => {
118
- const originals = originalAttrByEl.get(el);
119
- if (!originals)
120
- return;
121
- for (const { attr } of ATTRIBUTE_MARKS) {
122
- const original = originals.get(attr);
123
- if (original == null)
124
- continue;
125
- if (el.getAttribute(attr) === original)
126
- continue;
127
- try {
128
- el.setAttribute(attr, original);
129
- }
130
- catch {
131
- // ignore
132
- }
133
- }
134
- });
135
- }
136
- }
@@ -1,10 +0,0 @@
1
- export declare const DEFAULT_THROTTLE_MS = 150;
2
- export declare const DEFAULT_CRITICAL_BUFFER_PX = 200;
3
- export declare const DEFAULT_CRITICAL_MAX = 800;
4
- export declare const EXCLUDE_SELECTOR = "[data-lovalingo-exclude],[data-notranslate],[translate-no],[data-no-translate]";
5
- export declare const UNSAFE_CONTAINER_TAGS: Set<string>;
6
- export declare const ATTRIBUTE_MARKS: {
7
- attr: string;
8
- marker: string;
9
- }[];
10
- export declare const unsafeSelector: string;
@@ -1,12 +0,0 @@
1
- // Why: keep marker scans cheap while still capturing a small above-the-fold "critical slice" for first paint.
2
- export const DEFAULT_THROTTLE_MS = 150;
3
- export const DEFAULT_CRITICAL_BUFFER_PX = 200;
4
- export const DEFAULT_CRITICAL_MAX = 800;
5
- export const EXCLUDE_SELECTOR = "[data-lovalingo-exclude],[data-notranslate],[translate-no],[data-no-translate]";
6
- export const UNSAFE_CONTAINER_TAGS = new Set(["script", "style", "noscript", "template", "svg", "canvas"]);
7
- export const ATTRIBUTE_MARKS = [
8
- { attr: "title", marker: "data-lovalingo-title-original" },
9
- { attr: "aria-label", marker: "data-lovalingo-aria-label-original" },
10
- { attr: "placeholder", marker: "data-lovalingo-placeholder-original" },
11
- ];
12
- export const unsafeSelector = Array.from(UNSAFE_CONTAINER_TAGS).join(",");
@@ -1,2 +0,0 @@
1
- import type { CriticalFingerprint } from "./markerEngineTypes";
2
- export declare function getCriticalFingerprint(): CriticalFingerprint;