@lovalingo/lovalingo 0.5.28 → 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 +36 -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,82 +0,0 @@
1
- import { useEffect } from "react";
2
- import { processPath } from "../../utils/pathNormalizer";
3
- export function useNavigationPrefetch({ resolvedApiKey, apiBase, defaultLocale, locale, routing, allLocales, enhancedPathConfig, }) {
4
- // Navigation prefetch: warm the HTTP cache for bootstrap + page bundle before the user clicks (reduces EN→FR flash on SPA route changes).
5
- useEffect(() => {
6
- if (!resolvedApiKey)
7
- return;
8
- if (typeof window === "undefined" || typeof document === "undefined")
9
- return;
10
- const connection = navigator?.connection;
11
- if (connection?.saveData)
12
- return;
13
- if (typeof connection?.effectiveType === "string" && /(^|-)2g$/.test(connection.effectiveType))
14
- return;
15
- const prefetched = new Set();
16
- // Why: cap speculative requests to avoid flooding the network on pages with many links.
17
- const maxPrefetch = 40;
18
- const isAssetPath = (pathname) => {
19
- if (pathname === "/robots.txt" || pathname === "/sitemap.xml")
20
- return true;
21
- if (pathname.startsWith("/.well-known/"))
22
- return true;
23
- return /\.(?:png|jpg|jpeg|gif|svg|webp|avif|ico|css|js|map|json|xml|txt|pdf|zip|gz|br|woff2?|ttf|eot)$/i.test(pathname);
24
- };
25
- const pickLocaleForUrl = (url) => {
26
- if (routing === "path") {
27
- const segment = url.pathname.split("/")[1] || "";
28
- if (segment && allLocales.includes(segment))
29
- return segment;
30
- return locale;
31
- }
32
- const q = url.searchParams.get("t") || url.searchParams.get("locale");
33
- if (q && allLocales.includes(q))
34
- return q;
35
- return locale;
36
- };
37
- const onIntent = (event) => {
38
- if (prefetched.size >= maxPrefetch)
39
- return;
40
- const target = event.target;
41
- const anchor = target?.closest?.("a[href]");
42
- if (!anchor)
43
- return;
44
- const href = anchor.getAttribute("href") || "";
45
- if (!href || /^(?:#|mailto:|tel:|sms:|javascript:)/i.test(href))
46
- return;
47
- let url;
48
- try {
49
- url = new URL(href, window.location.origin);
50
- }
51
- catch {
52
- return;
53
- }
54
- if (url.origin !== window.location.origin)
55
- return;
56
- if (isAssetPath(url.pathname))
57
- return;
58
- const targetLocale = pickLocaleForUrl(url);
59
- if (!targetLocale || targetLocale === defaultLocale)
60
- return;
61
- const normalizedPath = processPath(url.pathname, enhancedPathConfig);
62
- const key = `${targetLocale}:${normalizedPath}`;
63
- if (prefetched.has(key))
64
- return;
65
- prefetched.add(key);
66
- const pathParam = `${url.pathname}${url.search}`;
67
- const bootstrapUrl = `${apiBase}/functions/v1/bootstrap?key=${encodeURIComponent(resolvedApiKey)}&locale=${encodeURIComponent(targetLocale)}&path=${encodeURIComponent(pathParam)}`;
68
- // Why: CF data plane serves page-scoped bundles only; keep prefetch aligned.
69
- const bundleUrl = `${apiBase}/functions/v1/bundle?key=${encodeURIComponent(resolvedApiKey)}&locale=${encodeURIComponent(targetLocale)}&path=${encodeURIComponent(pathParam)}&scoped=1`;
70
- void fetch(bootstrapUrl, { cache: "force-cache" }).catch(() => undefined);
71
- void fetch(bundleUrl, { cache: "force-cache" }).catch(() => undefined);
72
- };
73
- document.addEventListener("pointerover", onIntent, { passive: true });
74
- document.addEventListener("touchstart", onIntent, { passive: true });
75
- document.addEventListener("focusin", onIntent);
76
- return () => {
77
- document.removeEventListener("pointerover", onIntent);
78
- document.removeEventListener("touchstart", onIntent);
79
- document.removeEventListener("focusin", onIntent);
80
- };
81
- }, [allLocales, apiBase, defaultLocale, enhancedPathConfig, locale, resolvedApiKey, routing]);
82
- }
@@ -1,10 +0,0 @@
1
- import type React from "react";
2
- import type { LovalingoAPI } from "../../utils/api";
3
- type UsePageviewTrackingOptions = {
4
- apiRef: React.MutableRefObject<LovalingoAPI>;
5
- resolvedApiKey: string;
6
- };
7
- export declare function usePageviewTracking({ apiRef, resolvedApiKey }: UsePageviewTrackingOptions): {
8
- trackPageviewOnce: (path: string) => void;
9
- };
10
- export {};
@@ -1,44 +0,0 @@
1
- import { useCallback, useEffect, useRef } from "react";
2
- import { getCriticalFingerprint } from "../../utils/markerEngine";
3
- export function usePageviewTracking({ apiRef, resolvedApiKey }) {
4
- const lastPageviewRef = useRef("");
5
- const lastPageviewFingerprintRef = useRef("");
6
- const pageviewFingerprintTimeoutRef = useRef(null);
7
- const pageviewFingerprintRetryTimeoutRef = useRef(null);
8
- useEffect(() => {
9
- lastPageviewRef.current = "";
10
- lastPageviewFingerprintRef.current = "";
11
- }, [resolvedApiKey]);
12
- const trackPageviewOnce = useCallback((path) => {
13
- const next = (path || "").toString();
14
- if (!next)
15
- return;
16
- if (lastPageviewRef.current === next)
17
- return;
18
- lastPageviewRef.current = next;
19
- apiRef.current.trackPageview(next);
20
- const trySendFingerprint = () => {
21
- if (typeof window === "undefined")
22
- return;
23
- const markersReady = window.__lovalingoMarkersReady === true;
24
- if (!markersReady)
25
- return;
26
- const fp = getCriticalFingerprint();
27
- if (!fp || fp.critical_count <= 0)
28
- return;
29
- const signature = `${next}|${fp.critical_hash}|${fp.critical_count}`;
30
- if (lastPageviewFingerprintRef.current === signature)
31
- return;
32
- lastPageviewFingerprintRef.current = signature;
33
- apiRef.current.trackPageview(next, fp);
34
- };
35
- if (pageviewFingerprintTimeoutRef.current != null)
36
- window.clearTimeout(pageviewFingerprintTimeoutRef.current);
37
- if (pageviewFingerprintRetryTimeoutRef.current != null)
38
- window.clearTimeout(pageviewFingerprintRetryTimeoutRef.current);
39
- // Why: wait briefly for markers/content to settle before computing a critical fingerprint for change detection.
40
- pageviewFingerprintTimeoutRef.current = window.setTimeout(trySendFingerprint, 800);
41
- pageviewFingerprintRetryTimeoutRef.current = window.setTimeout(trySendFingerprint, 2000);
42
- }, [apiRef]);
43
- return { trackPageviewOnce };
44
- }
@@ -1,5 +0,0 @@
1
- export declare const PREHIDE_FAILSAFE_MS = 900;
2
- export declare function usePrehide(): {
3
- enablePrehide: (bgColor: string) => void;
4
- disablePrehide: () => void;
5
- };
@@ -1,72 +0,0 @@
1
- import { useCallback, useEffect, useRef } from "react";
2
- // Why: keep the no-flash "prehide" budget tight to improve FCP while still preventing perma-hide.
3
- export const PREHIDE_FAILSAFE_MS = 900;
4
- export function usePrehide() {
5
- const prehideStateRef = useRef({
6
- active: false,
7
- timeoutId: null,
8
- startedAtMs: null,
9
- prevHtmlVisibility: "",
10
- prevBodyVisibility: "",
11
- prevHtmlBg: "",
12
- prevBodyBg: "",
13
- });
14
- const forceDisablePrehide = useCallback(() => {
15
- if (typeof document === "undefined")
16
- return;
17
- const html = document.documentElement;
18
- const body = document.body;
19
- if (!html || !body)
20
- return;
21
- const state = prehideStateRef.current;
22
- if (state.timeoutId != null) {
23
- window.clearTimeout(state.timeoutId);
24
- state.timeoutId = null;
25
- }
26
- if (!state.active)
27
- return;
28
- state.active = false;
29
- state.startedAtMs = null;
30
- html.style.visibility = state.prevHtmlVisibility;
31
- body.style.visibility = state.prevBodyVisibility;
32
- html.style.backgroundColor = state.prevHtmlBg;
33
- body.style.backgroundColor = state.prevBodyBg;
34
- }, []);
35
- const enablePrehide = useCallback((bgColor) => {
36
- if (typeof document === "undefined")
37
- return;
38
- const html = document.documentElement;
39
- const body = document.body;
40
- if (!html || !body)
41
- return;
42
- const state = prehideStateRef.current;
43
- // Why: avoid "perma-hidden" pages when repeated navigation/errors keep prehide active; always hard-stop after a few seconds.
44
- if (state.active && state.startedAtMs != null && Date.now() - state.startedAtMs > PREHIDE_FAILSAFE_MS * 3) {
45
- forceDisablePrehide();
46
- }
47
- if (!state.active) {
48
- state.active = true;
49
- state.startedAtMs = Date.now();
50
- state.prevHtmlVisibility = html.style.visibility || "";
51
- state.prevBodyVisibility = body.style.visibility || "";
52
- state.prevHtmlBg = html.style.backgroundColor || "";
53
- state.prevBodyBg = body.style.backgroundColor || "";
54
- }
55
- html.style.visibility = "hidden";
56
- body.style.visibility = "hidden";
57
- if (bgColor) {
58
- html.style.backgroundColor = bgColor;
59
- body.style.backgroundColor = bgColor;
60
- }
61
- if (state.timeoutId != null) {
62
- return;
63
- }
64
- // Why: avoid a "perma-hide" when navigation events repeatedly re-trigger prehide and keep extending the timeout.
65
- state.timeoutId = window.setTimeout(() => forceDisablePrehide(), PREHIDE_FAILSAFE_MS);
66
- }, [forceDisablePrehide]);
67
- const disablePrehide = forceDisablePrehide;
68
- useEffect(() => {
69
- return () => disablePrehide();
70
- }, [disablePrehide]);
71
- return { enablePrehide, disablePrehide };
72
- }
@@ -1,7 +0,0 @@
1
- type UseSitemapLinkTagOptions = {
2
- enabled: boolean;
3
- resolvedApiKey: string;
4
- isSeoActive: () => boolean;
5
- };
6
- export declare function useSitemapLinkTag({ enabled, resolvedApiKey, isSeoActive }: UseSitemapLinkTagOptions): void;
7
- export {};
@@ -1,28 +0,0 @@
1
- import { useEffect } from "react";
2
- export function useSitemapLinkTag({ enabled, resolvedApiKey, isSeoActive }) {
3
- // Auto-inject sitemap link tag
4
- useEffect(() => {
5
- if (enabled && resolvedApiKey && isSeoActive()) {
6
- // Prefer same-origin /sitemap.xml so crawlers discover the canonical sitemap URL.
7
- // Reminder: /sitemap.xml should be published by the host app (recommended: build-time copy from Lovalingo CDN).
8
- const sitemapUrl = `${window.location.origin}/sitemap.xml`;
9
- // Check if link already exists to avoid duplicates
10
- const existingLink = document.querySelector(`link[rel="sitemap"][href="${sitemapUrl}"]`);
11
- if (existingLink)
12
- return;
13
- // Create and inject link tag
14
- const link = document.createElement("link");
15
- link.rel = "sitemap";
16
- link.type = "application/xml";
17
- link.href = sitemapUrl;
18
- document.head.appendChild(link);
19
- // Cleanup on unmount
20
- return () => {
21
- const linkToRemove = document.querySelector(`link[rel="sitemap"][href="${sitemapUrl}"]`);
22
- if (linkToRemove) {
23
- document.head.removeChild(linkToRemove);
24
- }
25
- };
26
- }
27
- }, [enabled, resolvedApiKey, isSeoActive]);
28
- }
@@ -1,14 +0,0 @@
1
- import type { MutableRefObject } from "react";
2
- import type { LovalingoAPI } from "../../utils/api";
3
- import { type NonLocalizedPathRule } from "../../utils/nonLocalizedPaths";
4
- export declare function useStringMissReporting(args: {
5
- apiRef: MutableRefObject<LovalingoAPI>;
6
- resolvedApiKey: string;
7
- locale: string;
8
- defaultLocale: string;
9
- routing: "path" | "query";
10
- allLocales: string[];
11
- nonLocalizedPaths: NonLocalizedPathRule[];
12
- isLoading: boolean;
13
- mode: "dom";
14
- }): void;
@@ -1,155 +0,0 @@
1
- import { useCallback, useEffect, useRef } from "react";
2
- import { addActiveTranslations, applyActiveTranslations, scanDomForMisses } from "../../utils/markerEngine";
3
- import { logDebug } from "../../utils/logger";
4
- import { isNonLocalizedPath, stripLocalePrefix } from "../../utils/nonLocalizedPaths";
5
- // Why: throttle miss scans so we stay responsive on DOM-heavy pages.
6
- const MISS_SCAN_THROTTLE_MS = 600;
7
- // Why: allow large pages to report plenty of misses while keeping payloads bounded.
8
- const MISS_MAX_PER_PAGE = 500;
9
- function looksLike404Page() {
10
- if (typeof document === "undefined")
11
- return false;
12
- // 1. Meta tag (Explicit opt-in for SPAs)
13
- const meta = document.querySelector('meta[name="lovalingo:status"]');
14
- if (meta && meta.getAttribute("content") === "404")
15
- return true;
16
- // 2. Title Heuristics
17
- const title = (document.title || "").toLowerCase();
18
- // Why: detect common 404 title patterns to avoid reporting misses on ghost pages.
19
- if (/page not found|seite nicht gefunden|article not found|error 404|page missing|does not exist/.test(title))
20
- return true;
21
- // 3. H1 Heuristics
22
- const h1 = document.querySelector("h1");
23
- if (h1) {
24
- const txt = (h1.innerText || "").toLowerCase();
25
- if (/page not found|seite nicht gefunden|article not found|error 404/.test(txt))
26
- return true;
27
- if (txt.includes("404") && txt.length < 50)
28
- return true;
29
- }
30
- return false;
31
- }
32
- export function useStringMissReporting(args) {
33
- const pendingRef = useRef(new Set());
34
- const seenRef = useRef(new Set());
35
- const scheduledRef = useRef(null);
36
- const inFlightRef = useRef(false);
37
- useEffect(() => {
38
- pendingRef.current.clear();
39
- seenRef.current.clear();
40
- }, [args.locale]);
41
- const shouldSkip = useCallback(() => {
42
- if (typeof window === "undefined" || typeof document === "undefined")
43
- return true;
44
- if (looksLike404Page())
45
- return true;
46
- const disableLiveMisses = Boolean(window.__lovalingoDisableMisses);
47
- if (disableLiveMisses)
48
- return true;
49
- if (!args.resolvedApiKey || args.mode !== "dom")
50
- return true;
51
- if (args.isLoading)
52
- return true;
53
- if (args.locale === args.defaultLocale)
54
- return true;
55
- if (args.routing === "path") {
56
- const stripped = stripLocalePrefix(window.location.pathname, args.allLocales);
57
- if (isNonLocalizedPath(stripped, args.nonLocalizedPaths))
58
- return true;
59
- }
60
- return false;
61
- }, [args.allLocales, args.defaultLocale, args.isLoading, args.locale, args.mode, args.nonLocalizedPaths, args.resolvedApiKey, args.routing]);
62
- const runScan = useCallback(async () => {
63
- scheduledRef.current = null;
64
- if (shouldSkip())
65
- return;
66
- if (!document.body)
67
- return;
68
- if (inFlightRef.current)
69
- return;
70
- const ignore = new Set([...pendingRef.current, ...seenRef.current]);
71
- const { misses } = scanDomForMisses({ max: MISS_MAX_PER_PAGE, ignore });
72
- if (misses.length === 0)
73
- return;
74
- logDebug(`[Lovalingo] Live misses detected: ${misses.length}`);
75
- misses.forEach((miss) => pendingRef.current.add(miss.source_text));
76
- inFlightRef.current = true;
77
- try {
78
- const response = await args.apiRef.current.reportStringMisses(args.locale, misses, {
79
- sourceLocale: args.defaultLocale,
80
- locales: args.allLocales,
81
- });
82
- if (response?.ignored) {
83
- for (const miss of misses) {
84
- pendingRef.current.delete(miss.source_text);
85
- seenRef.current.add(miss.source_text);
86
- }
87
- return;
88
- }
89
- const translations = Array.isArray(response?.translations) ? response.translations : [];
90
- const pii = Array.isArray(response?.pii) ? response.pii : [];
91
- logDebug(`[Lovalingo] Live misses resolved`, { translations: translations.length, pii: pii.length });
92
- const resolved = new Set();
93
- pii.forEach((text) => resolved.add(text));
94
- translations.forEach((row) => {
95
- if (row?.source_text)
96
- resolved.add(row.source_text);
97
- });
98
- if (translations.length > 0) {
99
- const additions = translations
100
- .map((row) => ({
101
- source_text: row.source_text,
102
- translated_text: row.translated_text,
103
- source_locale: args.defaultLocale,
104
- target_locale: args.locale,
105
- }))
106
- .filter((row) => row.source_text && row.translated_text);
107
- if (additions.length > 0) {
108
- addActiveTranslations(additions);
109
- applyActiveTranslations(document.body);
110
- }
111
- }
112
- for (const miss of misses) {
113
- pendingRef.current.delete(miss.source_text);
114
- if (resolved.has(miss.source_text)) {
115
- seenRef.current.add(miss.source_text);
116
- }
117
- }
118
- }
119
- catch {
120
- for (const miss of misses) {
121
- pendingRef.current.delete(miss.source_text);
122
- }
123
- }
124
- finally {
125
- inFlightRef.current = false;
126
- }
127
- }, [args.apiRef, args.defaultLocale, args.locale, shouldSkip]);
128
- const scheduleScan = useCallback(() => {
129
- if (scheduledRef.current != null)
130
- return;
131
- scheduledRef.current = window.setTimeout(() => {
132
- void runScan();
133
- }, MISS_SCAN_THROTTLE_MS);
134
- }, [runScan]);
135
- useEffect(() => {
136
- if (shouldSkip())
137
- return;
138
- scheduleScan();
139
- if (!document.body)
140
- return;
141
- const observer = new MutationObserver(() => scheduleScan());
142
- observer.observe(document.body, {
143
- childList: true,
144
- subtree: true,
145
- characterData: true,
146
- });
147
- return () => {
148
- observer.disconnect();
149
- if (scheduledRef.current != null) {
150
- window.clearTimeout(scheduledRef.current);
151
- scheduledRef.current = null;
152
- }
153
- };
154
- }, [scheduleScan, shouldSkip]);
155
- }
@@ -1,6 +0,0 @@
1
- export declare const useLovalingo: () => {
2
- locale: string;
3
- setLocale: (locale: string) => void;
4
- isLoading: boolean;
5
- config: import("..").LovalingoConfig;
6
- };
@@ -1,14 +0,0 @@
1
- import { useContext } from 'react';
2
- import { LovalingoContext } from '../context/LovalingoContext';
3
- export const useLovalingo = () => {
4
- const context = useContext(LovalingoContext);
5
- if (!context) {
6
- throw new Error('useLovalingo must be used within LovalingoProvider');
7
- }
8
- return {
9
- locale: context.locale,
10
- setLocale: context.setLocale,
11
- isLoading: context.isLoading,
12
- config: context.config,
13
- };
14
- };
@@ -1,5 +0,0 @@
1
- export declare const useLovalingoEdit: () => {
2
- editMode: boolean;
3
- toggleEditMode: () => void;
4
- excludeElement: (selector: string) => Promise<void>;
5
- };
@@ -1,13 +0,0 @@
1
- import { useContext } from 'react';
2
- import { LovalingoContext } from '../context/LovalingoContext';
3
- export const useLovalingoEdit = () => {
4
- const context = useContext(LovalingoContext);
5
- if (!context) {
6
- throw new Error('useLovalingoEdit must be used within LovalingoProvider');
7
- }
8
- return {
9
- editMode: context.editMode,
10
- toggleEditMode: context.toggleEditMode,
11
- excludeElement: context.excludeElement,
12
- };
13
- };
@@ -1,4 +0,0 @@
1
- export declare const useLovalingoTranslate: () => {
2
- translateElement: (element: HTMLElement) => void;
3
- translateDOM: () => void;
4
- };
@@ -1,12 +0,0 @@
1
- import { useContext } from 'react';
2
- import { LovalingoContext } from '../context/LovalingoContext';
3
- export const useLovalingoTranslate = () => {
4
- const context = useContext(LovalingoContext);
5
- if (!context) {
6
- throw new Error('useLovalingoTranslate must be used within LovalingoProvider');
7
- }
8
- return {
9
- translateElement: context.translateElement,
10
- translateDOM: context.translateDOM,
11
- };
12
- };
@@ -1,16 +0,0 @@
1
- /**
2
- * useLang - Get the current language from the URL
3
- *
4
- * Works with LangRouter to extract language from /:lang/* routes
5
- *
6
- * Usage:
7
- * ```tsx
8
- * function MyComponent() {
9
- * const lang = useLang(); // 'en', 'fr', 'de', etc.
10
- * return <div>Current language: {lang}</div>;
11
- * }
12
- * ```
13
- *
14
- * @returns Current language code (e.g., 'en', 'fr', 'de')
15
- */
16
- export declare function useLang(): string;
@@ -1,23 +0,0 @@
1
- import { useParams } from 'react-router-dom';
2
- import { useContext } from 'react';
3
- import { LangContext } from '../context/LangContext';
4
- /**
5
- * useLang - Get the current language from the URL
6
- *
7
- * Works with LangRouter to extract language from /:lang/* routes
8
- *
9
- * Usage:
10
- * ```tsx
11
- * function MyComponent() {
12
- * const lang = useLang(); // 'en', 'fr', 'de', etc.
13
- * return <div>Current language: {lang}</div>;
14
- * }
15
- * ```
16
- *
17
- * @returns Current language code (e.g., 'en', 'fr', 'de')
18
- */
19
- export function useLang() {
20
- const ctxLang = useContext(LangContext);
21
- const { lang } = useParams();
22
- return ctxLang ?? lang ?? 'en'; // Fallback to 'en' if not found
23
- }
@@ -1,24 +0,0 @@
1
- /**
2
- * useLangNavigate - Get a language-aware navigate function
3
- *
4
- * Automatically prepends the current language to navigation paths
5
- *
6
- * Usage:
7
- * ```tsx
8
- * function MyComponent() {
9
- * const navigate = useLangNavigate();
10
- *
11
- * const goToPricing = () => {
12
- * navigate('pricing'); // Goes to /en/pricing or /fr/pricing automatically
13
- * };
14
- *
15
- * return <button onClick={goToPricing}>Pricing</button>;
16
- * }
17
- * ```
18
- *
19
- * @returns Navigate function that auto-prepends language
20
- */
21
- export declare function useLangNavigate(): (path: string, options?: {
22
- replace?: boolean;
23
- state?: unknown;
24
- }) => void;
@@ -1,40 +0,0 @@
1
- import { useNavigate } from 'react-router-dom';
2
- import { useCallback, useContext } from 'react';
3
- import { useLang } from './useLang';
4
- import { LangRoutingContext } from '../context/LangRoutingContext';
5
- import { isNonLocalizedPath } from '../utils/nonLocalizedPaths';
6
- /**
7
- * useLangNavigate - Get a language-aware navigate function
8
- *
9
- * Automatically prepends the current language to navigation paths
10
- *
11
- * Usage:
12
- * ```tsx
13
- * function MyComponent() {
14
- * const navigate = useLangNavigate();
15
- *
16
- * const goToPricing = () => {
17
- * navigate('pricing'); // Goes to /en/pricing or /fr/pricing automatically
18
- * };
19
- *
20
- * return <button onClick={goToPricing}>Pricing</button>;
21
- * }
22
- * ```
23
- *
24
- * @returns Navigate function that auto-prepends language
25
- */
26
- export function useLangNavigate() {
27
- const navigate = useNavigate();
28
- const lang = useLang();
29
- const routing = useContext(LangRoutingContext);
30
- return useCallback((path, options) => {
31
- const trimmed = (path || "").toString().trim();
32
- if (!trimmed)
33
- return;
34
- const normalized = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
35
- const fullPath = isNonLocalizedPath(normalized, routing.nonLocalizedPaths)
36
- ? normalized
37
- : `/${lang}${normalized}`;
38
- navigate(fullPath, options);
39
- }, [lang, navigate, routing.nonLocalizedPaths]);
40
- }
@@ -1 +0,0 @@
1
- export { useLovalingo } from "./useAixster";
@@ -1 +0,0 @@
1
- export { useLovalingo } from "./useAixster";
@@ -1 +0,0 @@
1
- export { useLovalingoEdit } from "./useAixsterEdit";
@@ -1 +0,0 @@
1
- export { useLovalingoEdit } from "./useAixsterEdit";
@@ -1 +0,0 @@
1
- export { useLovalingoTranslate } from "./useAixsterTranslate";
@@ -1 +0,0 @@
1
- export { useLovalingoTranslate } from "./useAixsterTranslate";