@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.
- package/README.md +36 -0
- package/dist/chunk-2FZR2AKF.mjs +88 -0
- package/dist/chunk-7D5LBV45.mjs +46 -0
- package/dist/chunk-CJOSN7RA.mjs +90 -0
- package/dist/chunk-VAHA2TOX.mjs +3440 -0
- package/dist/chunk-ZMRCSUM7.mjs +26 -0
- package/dist/chunk-ZVYKEEUF.mjs +220 -0
- package/dist/core.d.mts +131 -0
- package/dist/core.d.ts +131 -0
- package/dist/core.js +3561 -0
- package/dist/core.mjs +19 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.d.ts +5 -25
- package/dist/index.js +3885 -28
- package/dist/index.mjs +33 -0
- package/dist/react-router.d.mts +101 -0
- package/dist/react-router.d.ts +101 -0
- package/dist/react-router.js +353 -0
- package/dist/react-router.mjs +14 -0
- package/dist/tanstack-router.d.mts +22 -0
- package/dist/tanstack-router.d.ts +22 -0
- package/dist/tanstack-router.js +162 -0
- package/dist/tanstack-router.mjs +8 -0
- package/package.json +34 -3
- package/dist/__tests__/languageFlags.test.d.ts +0 -1
- package/dist/__tests__/languageFlags.test.js +0 -42
- package/dist/__tests__/mergeEntitlements.test.d.ts +0 -1
- package/dist/__tests__/mergeEntitlements.test.js +0 -27
- package/dist/components/AixsterProvider.d.ts +0 -1
- package/dist/components/AixsterProvider.js +0 -1
- package/dist/components/LangLink.d.ts +0 -20
- package/dist/components/LangLink.js +0 -38
- package/dist/components/LangRouter.d.ts +0 -37
- package/dist/components/LangRouter.js +0 -191
- package/dist/components/LanguageSwitcher.d.ts +0 -17
- package/dist/components/LanguageSwitcher.js +0 -257
- package/dist/components/LovalingoProvider.d.ts +0 -10
- package/dist/components/LovalingoProvider.js +0 -413
- package/dist/components/NavigationOverlay.d.ts +0 -6
- package/dist/components/NavigationOverlay.js +0 -22
- package/dist/components/provider/__tests__/seoUtils.test.d.ts +0 -1
- package/dist/components/provider/__tests__/seoUtils.test.js +0 -13
- package/dist/components/provider/editModeUtils.d.ts +0 -6
- package/dist/components/provider/editModeUtils.js +0 -59
- package/dist/components/provider/localeUtils.d.ts +0 -8
- package/dist/components/provider/localeUtils.js +0 -46
- package/dist/components/provider/providerConstants.d.ts +0 -12
- package/dist/components/provider/providerConstants.js +0 -11
- package/dist/components/provider/seoUtils.d.ts +0 -8
- package/dist/components/provider/seoUtils.js +0 -118
- package/dist/components/provider/useEditModeOverlay.d.ts +0 -7
- package/dist/components/provider/useEditModeOverlay.js +0 -134
- package/dist/components/provider/useHistoryNavigationPatch.d.ts +0 -3
- package/dist/components/provider/useHistoryNavigationPatch.js +0 -47
- package/dist/components/provider/useProviderCache.d.ts +0 -12
- package/dist/components/provider/useProviderCache.js +0 -82
- package/dist/context/AixsterContext.d.ts +0 -3
- package/dist/context/AixsterContext.js +0 -2
- package/dist/context/LangContext.d.ts +0 -1
- package/dist/context/LangContext.js +0 -2
- package/dist/context/LangRoutingContext.d.ts +0 -8
- package/dist/context/LangRoutingContext.js +0 -7
- package/dist/context/LovalingoContext.d.ts +0 -1
- package/dist/context/LovalingoContext.js +0 -1
- package/dist/hooks/provider/useBundleLoading.d.ts +0 -33
- package/dist/hooks/provider/useBundleLoading.js +0 -380
- package/dist/hooks/provider/useDomRules.d.ts +0 -15
- package/dist/hooks/provider/useDomRules.js +0 -38
- package/dist/hooks/provider/useLinkAutoPrefix.d.ts +0 -12
- package/dist/hooks/provider/useLinkAutoPrefix.js +0 -146
- package/dist/hooks/provider/useNavigationPrefetch.d.ts +0 -12
- package/dist/hooks/provider/useNavigationPrefetch.js +0 -82
- package/dist/hooks/provider/usePageviewTracking.d.ts +0 -10
- package/dist/hooks/provider/usePageviewTracking.js +0 -44
- package/dist/hooks/provider/usePrehide.d.ts +0 -5
- package/dist/hooks/provider/usePrehide.js +0 -72
- package/dist/hooks/provider/useSitemapLinkTag.d.ts +0 -7
- package/dist/hooks/provider/useSitemapLinkTag.js +0 -28
- package/dist/hooks/provider/useStringMissReporting.d.ts +0 -14
- package/dist/hooks/provider/useStringMissReporting.js +0 -155
- package/dist/hooks/useAixster.d.ts +0 -6
- package/dist/hooks/useAixster.js +0 -14
- package/dist/hooks/useAixsterEdit.d.ts +0 -5
- package/dist/hooks/useAixsterEdit.js +0 -13
- package/dist/hooks/useAixsterTranslate.d.ts +0 -4
- package/dist/hooks/useAixsterTranslate.js +0 -12
- package/dist/hooks/useLang.d.ts +0 -16
- package/dist/hooks/useLang.js +0 -23
- package/dist/hooks/useLangNavigate.d.ts +0 -24
- package/dist/hooks/useLangNavigate.js +0 -40
- package/dist/hooks/useLovalingo.d.ts +0 -1
- package/dist/hooks/useLovalingo.js +0 -1
- package/dist/hooks/useLovalingoEdit.d.ts +0 -1
- package/dist/hooks/useLovalingoEdit.js +0 -1
- package/dist/hooks/useLovalingoTranslate.d.ts +0 -1
- package/dist/hooks/useLovalingoTranslate.js +0 -1
- package/dist/types.d.ts +0 -76
- package/dist/types.js +0 -1
- package/dist/utils/api.d.ts +0 -42
- package/dist/utils/api.js +0 -395
- package/dist/utils/apiTypes.d.ts +0 -78
- package/dist/utils/apiTypes.js +0 -1
- package/dist/utils/apiUtils.d.ts +0 -4
- package/dist/utils/apiUtils.js +0 -54
- package/dist/utils/domRules.d.ts +0 -2
- package/dist/utils/domRules.js +0 -150
- package/dist/utils/hash.d.ts +0 -9
- package/dist/utils/hash.js +0 -27
- package/dist/utils/languageFlags.d.ts +0 -7
- package/dist/utils/languageFlags.js +0 -90
- package/dist/utils/logger.d.ts +0 -3
- package/dist/utils/logger.js +0 -40
- package/dist/utils/markerEngine.d.ts +0 -12
- package/dist/utils/markerEngine.js +0 -109
- package/dist/utils/markerEngineApply.d.ts +0 -3
- package/dist/utils/markerEngineApply.js +0 -136
- package/dist/utils/markerEngineConstants.d.ts +0 -10
- package/dist/utils/markerEngineConstants.js +0 -12
- package/dist/utils/markerEngineCritical.d.ts +0 -2
- package/dist/utils/markerEngineCritical.js +0 -98
- package/dist/utils/markerEngineDomUtils.d.ts +0 -8
- package/dist/utils/markerEngineDomUtils.js +0 -74
- package/dist/utils/markerEngineFilters.d.ts +0 -2
- package/dist/utils/markerEngineFilters.js +0 -26
- package/dist/utils/markerEngineMisses.d.ts +0 -5
- package/dist/utils/markerEngineMisses.js +0 -81
- package/dist/utils/markerEngineOriginals.d.ts +0 -5
- package/dist/utils/markerEngineOriginals.js +0 -29
- package/dist/utils/markerEngineScan.d.ts +0 -5
- package/dist/utils/markerEngineScan.js +0 -162
- package/dist/utils/markerEngineState.d.ts +0 -4
- package/dist/utils/markerEngineState.js +0 -14
- package/dist/utils/markerEngineStats.d.ts +0 -3
- package/dist/utils/markerEngineStats.js +0 -28
- package/dist/utils/markerEngineTranslations.d.ts +0 -3
- package/dist/utils/markerEngineTranslations.js +0 -49
- package/dist/utils/markerEngineTypes.d.ts +0 -62
- package/dist/utils/markerEngineTypes.js +0 -1
- package/dist/utils/markerEngineViewport.d.ts +0 -2
- package/dist/utils/markerEngineViewport.js +0 -27
- package/dist/utils/mergeEntitlements.d.ts +0 -2
- package/dist/utils/mergeEntitlements.js +0 -7
- package/dist/utils/nonLocalizedPaths.d.ts +0 -12
- package/dist/utils/nonLocalizedPaths.js +0 -136
- package/dist/utils/pathNormalizer.d.ts +0 -49
- package/dist/utils/pathNormalizer.js +0 -115
- package/dist/version.d.ts +0 -1
- package/dist/version.js +0 -1
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LanguageSwitcher,
|
|
3
|
+
LovalingoProvider,
|
|
4
|
+
VERSION,
|
|
5
|
+
useLovalingo,
|
|
6
|
+
useLovalingoEdit,
|
|
7
|
+
useLovalingoTranslate
|
|
8
|
+
} from "./chunk-VAHA2TOX.mjs";
|
|
9
|
+
import {
|
|
10
|
+
LangLink,
|
|
11
|
+
LangRouter,
|
|
12
|
+
useLang,
|
|
13
|
+
useLangNavigate
|
|
14
|
+
} from "./chunk-ZVYKEEUF.mjs";
|
|
15
|
+
import "./chunk-7D5LBV45.mjs";
|
|
16
|
+
import {
|
|
17
|
+
createLovalingoTanStackRewrite
|
|
18
|
+
} from "./chunk-CJOSN7RA.mjs";
|
|
19
|
+
import "./chunk-ZMRCSUM7.mjs";
|
|
20
|
+
import "./chunk-2FZR2AKF.mjs";
|
|
21
|
+
export {
|
|
22
|
+
LangLink,
|
|
23
|
+
LangRouter,
|
|
24
|
+
LanguageSwitcher,
|
|
25
|
+
LovalingoProvider,
|
|
26
|
+
VERSION,
|
|
27
|
+
createLovalingoTanStackRewrite,
|
|
28
|
+
useLang,
|
|
29
|
+
useLangNavigate,
|
|
30
|
+
useLovalingo,
|
|
31
|
+
useLovalingoEdit,
|
|
32
|
+
useLovalingoTranslate
|
|
33
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { LinkProps } from 'react-router-dom';
|
|
3
|
+
|
|
4
|
+
interface LangRouterProps {
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
defaultLang: string;
|
|
7
|
+
langs: string[];
|
|
8
|
+
navigateRef?: React.MutableRefObject<((path: string) => void) | undefined>;
|
|
9
|
+
apiBase?: string;
|
|
10
|
+
apiKey?: string;
|
|
11
|
+
publicAnonKey?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* LangRouter - Drop-in replacement for BrowserRouter that automatically handles language routing
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* ```tsx
|
|
18
|
+
* const navigateRef = useRef();
|
|
19
|
+
*
|
|
20
|
+
* <LangRouter defaultLang="en" langs={['en', 'fr', 'de', 'ko']} navigateRef={navigateRef}>
|
|
21
|
+
* <Routes>
|
|
22
|
+
* <Route path="/" element={<Home />} />
|
|
23
|
+
* <Route path="home" element={<Home />} />
|
|
24
|
+
* <Route path="pricing" element={<Pricing />} />
|
|
25
|
+
* </Routes>
|
|
26
|
+
* </LangRouter>
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* This automatically creates routes:
|
|
30
|
+
* - /en (root)
|
|
31
|
+
* - /en/home
|
|
32
|
+
* - /en/pricing
|
|
33
|
+
* - /fr (root)
|
|
34
|
+
* - /fr/home
|
|
35
|
+
* - /fr/pricing
|
|
36
|
+
* - etc.
|
|
37
|
+
*/
|
|
38
|
+
declare function LangRouter({ children, defaultLang, langs, navigateRef, apiBase, apiKey, publicAnonKey }: LangRouterProps): React.JSX.Element;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* LangLink - Language-aware Link component
|
|
42
|
+
*
|
|
43
|
+
* Automatically prepends the current language to all navigation paths
|
|
44
|
+
*
|
|
45
|
+
* Usage:
|
|
46
|
+
* ```tsx
|
|
47
|
+
* // Instead of:
|
|
48
|
+
* <Link to={`/${locale}/pricing`}>Pricing</Link>
|
|
49
|
+
*
|
|
50
|
+
* // Just write:
|
|
51
|
+
* <LangLink to="pricing">Pricing</LangLink>
|
|
52
|
+
* // Automatically becomes /en/pricing or /fr/pricing
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* All props from React Router's <Link> are supported
|
|
56
|
+
*/
|
|
57
|
+
declare function LangLink({ to, ...props }: LinkProps): React.JSX.Element;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* useLang - Get the current language from the URL
|
|
61
|
+
*
|
|
62
|
+
* Works with LangRouter to extract language from /:lang/* routes
|
|
63
|
+
*
|
|
64
|
+
* Usage:
|
|
65
|
+
* ```tsx
|
|
66
|
+
* function MyComponent() {
|
|
67
|
+
* const lang = useLang(); // 'en', 'fr', 'de', etc.
|
|
68
|
+
* return <div>Current language: {lang}</div>;
|
|
69
|
+
* }
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* @returns Current language code (e.g., 'en', 'fr', 'de')
|
|
73
|
+
*/
|
|
74
|
+
declare function useLang(): string;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* useLangNavigate - Get a language-aware navigate function
|
|
78
|
+
*
|
|
79
|
+
* Automatically prepends the current language to navigation paths
|
|
80
|
+
*
|
|
81
|
+
* Usage:
|
|
82
|
+
* ```tsx
|
|
83
|
+
* function MyComponent() {
|
|
84
|
+
* const navigate = useLangNavigate();
|
|
85
|
+
*
|
|
86
|
+
* const goToPricing = () => {
|
|
87
|
+
* navigate('pricing'); // Goes to /en/pricing or /fr/pricing automatically
|
|
88
|
+
* };
|
|
89
|
+
*
|
|
90
|
+
* return <button onClick={goToPricing}>Pricing</button>;
|
|
91
|
+
* }
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* @returns Navigate function that auto-prepends language
|
|
95
|
+
*/
|
|
96
|
+
declare function useLangNavigate(): (path: string, options?: {
|
|
97
|
+
replace?: boolean;
|
|
98
|
+
state?: unknown;
|
|
99
|
+
}) => void;
|
|
100
|
+
|
|
101
|
+
export { LangLink, LangRouter, useLang, useLangNavigate };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { LinkProps } from 'react-router-dom';
|
|
3
|
+
|
|
4
|
+
interface LangRouterProps {
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
defaultLang: string;
|
|
7
|
+
langs: string[];
|
|
8
|
+
navigateRef?: React.MutableRefObject<((path: string) => void) | undefined>;
|
|
9
|
+
apiBase?: string;
|
|
10
|
+
apiKey?: string;
|
|
11
|
+
publicAnonKey?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* LangRouter - Drop-in replacement for BrowserRouter that automatically handles language routing
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* ```tsx
|
|
18
|
+
* const navigateRef = useRef();
|
|
19
|
+
*
|
|
20
|
+
* <LangRouter defaultLang="en" langs={['en', 'fr', 'de', 'ko']} navigateRef={navigateRef}>
|
|
21
|
+
* <Routes>
|
|
22
|
+
* <Route path="/" element={<Home />} />
|
|
23
|
+
* <Route path="home" element={<Home />} />
|
|
24
|
+
* <Route path="pricing" element={<Pricing />} />
|
|
25
|
+
* </Routes>
|
|
26
|
+
* </LangRouter>
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* This automatically creates routes:
|
|
30
|
+
* - /en (root)
|
|
31
|
+
* - /en/home
|
|
32
|
+
* - /en/pricing
|
|
33
|
+
* - /fr (root)
|
|
34
|
+
* - /fr/home
|
|
35
|
+
* - /fr/pricing
|
|
36
|
+
* - etc.
|
|
37
|
+
*/
|
|
38
|
+
declare function LangRouter({ children, defaultLang, langs, navigateRef, apiBase, apiKey, publicAnonKey }: LangRouterProps): React.JSX.Element;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* LangLink - Language-aware Link component
|
|
42
|
+
*
|
|
43
|
+
* Automatically prepends the current language to all navigation paths
|
|
44
|
+
*
|
|
45
|
+
* Usage:
|
|
46
|
+
* ```tsx
|
|
47
|
+
* // Instead of:
|
|
48
|
+
* <Link to={`/${locale}/pricing`}>Pricing</Link>
|
|
49
|
+
*
|
|
50
|
+
* // Just write:
|
|
51
|
+
* <LangLink to="pricing">Pricing</LangLink>
|
|
52
|
+
* // Automatically becomes /en/pricing or /fr/pricing
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* All props from React Router's <Link> are supported
|
|
56
|
+
*/
|
|
57
|
+
declare function LangLink({ to, ...props }: LinkProps): React.JSX.Element;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* useLang - Get the current language from the URL
|
|
61
|
+
*
|
|
62
|
+
* Works with LangRouter to extract language from /:lang/* routes
|
|
63
|
+
*
|
|
64
|
+
* Usage:
|
|
65
|
+
* ```tsx
|
|
66
|
+
* function MyComponent() {
|
|
67
|
+
* const lang = useLang(); // 'en', 'fr', 'de', etc.
|
|
68
|
+
* return <div>Current language: {lang}</div>;
|
|
69
|
+
* }
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* @returns Current language code (e.g., 'en', 'fr', 'de')
|
|
73
|
+
*/
|
|
74
|
+
declare function useLang(): string;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* useLangNavigate - Get a language-aware navigate function
|
|
78
|
+
*
|
|
79
|
+
* Automatically prepends the current language to navigation paths
|
|
80
|
+
*
|
|
81
|
+
* Usage:
|
|
82
|
+
* ```tsx
|
|
83
|
+
* function MyComponent() {
|
|
84
|
+
* const navigate = useLangNavigate();
|
|
85
|
+
*
|
|
86
|
+
* const goToPricing = () => {
|
|
87
|
+
* navigate('pricing'); // Goes to /en/pricing or /fr/pricing automatically
|
|
88
|
+
* };
|
|
89
|
+
*
|
|
90
|
+
* return <button onClick={goToPricing}>Pricing</button>;
|
|
91
|
+
* }
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* @returns Navigate function that auto-prepends language
|
|
95
|
+
*/
|
|
96
|
+
declare function useLangNavigate(): (path: string, options?: {
|
|
97
|
+
replace?: boolean;
|
|
98
|
+
state?: unknown;
|
|
99
|
+
}) => void;
|
|
100
|
+
|
|
101
|
+
export { LangLink, LangRouter, useLang, useLangNavigate };
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/react-router.tsx
|
|
31
|
+
var react_router_exports = {};
|
|
32
|
+
__export(react_router_exports, {
|
|
33
|
+
LangLink: () => LangLink,
|
|
34
|
+
LangRouter: () => LangRouter,
|
|
35
|
+
useLang: () => useLang,
|
|
36
|
+
useLangNavigate: () => useLangNavigate
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(react_router_exports);
|
|
39
|
+
|
|
40
|
+
// src/components/LangRouter.tsx
|
|
41
|
+
var import_react3 = __toESM(require("react"));
|
|
42
|
+
var import_react_router_dom = require("react-router-dom");
|
|
43
|
+
|
|
44
|
+
// src/context/LangContext.ts
|
|
45
|
+
var import_react = require("react");
|
|
46
|
+
var LangContext = (0, import_react.createContext)(null);
|
|
47
|
+
|
|
48
|
+
// src/context/LangRoutingContext.ts
|
|
49
|
+
var import_react2 = require("react");
|
|
50
|
+
var LangRoutingContext = (0, import_react2.createContext)({
|
|
51
|
+
defaultLang: "",
|
|
52
|
+
nonLocalizedPaths: [],
|
|
53
|
+
inactivePages: [],
|
|
54
|
+
status: "unknown"
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// src/utils/nonLocalizedPaths.ts
|
|
58
|
+
var GLOBAL_NON_LOCALIZED_APP_PATHS = /* @__PURE__ */ new Set(["/robots.txt", "/sitemap.xml"]);
|
|
59
|
+
function isGlobalNonLocalizedPath(pathname) {
|
|
60
|
+
const input = (pathname || "").toString();
|
|
61
|
+
if (!input.startsWith("/")) return false;
|
|
62
|
+
if (GLOBAL_NON_LOCALIZED_APP_PATHS.has(input)) return true;
|
|
63
|
+
if (input.startsWith("/.well-known/")) return true;
|
|
64
|
+
return /\.(?:png|jpg|jpeg|gif|svg|webp|avif|ico|css|js|map|json|xml|txt|pdf|zip|gz|br|woff2?|ttf|eot)$/i.test(input);
|
|
65
|
+
}
|
|
66
|
+
function matchesNonLocalizedRules(pathname, rules) {
|
|
67
|
+
const input = (pathname || "").toString();
|
|
68
|
+
if (!input.startsWith("/")) return false;
|
|
69
|
+
if (!Array.isArray(rules) || rules.length === 0) return false;
|
|
70
|
+
for (const rule of rules) {
|
|
71
|
+
const pattern = typeof rule?.pattern === "string" ? rule.pattern : "";
|
|
72
|
+
const matchType = rule?.match_type;
|
|
73
|
+
if (!pattern) continue;
|
|
74
|
+
if (matchType === "exact") {
|
|
75
|
+
if (input === pattern) return true;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (matchType === "prefix") {
|
|
79
|
+
if (input === pattern) return true;
|
|
80
|
+
const normalizedPrefix = pattern.endsWith("/") ? pattern.slice(0, -1) : pattern;
|
|
81
|
+
if (!normalizedPrefix || normalizedPrefix === "/") return true;
|
|
82
|
+
if (input.startsWith(`${normalizedPrefix}/`)) return true;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (matchType === "regex") {
|
|
86
|
+
try {
|
|
87
|
+
if (new RegExp(pattern).test(input)) return true;
|
|
88
|
+
} catch {
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
function isNonLocalizedPath(pathname, rules) {
|
|
95
|
+
return isGlobalNonLocalizedPath(pathname) || matchesNonLocalizedRules(pathname, rules);
|
|
96
|
+
}
|
|
97
|
+
function parseBootstrapNonLocalizedPaths(value) {
|
|
98
|
+
if (!Array.isArray(value)) return [];
|
|
99
|
+
const out = [];
|
|
100
|
+
for (const row of value) {
|
|
101
|
+
if (!row || typeof row !== "object") continue;
|
|
102
|
+
const record = row;
|
|
103
|
+
const pattern = typeof record.pattern === "string" ? record.pattern.trim() : "";
|
|
104
|
+
const match_type = typeof record.match_type === "string" ? record.match_type.trim() : "";
|
|
105
|
+
if (!pattern) continue;
|
|
106
|
+
if (match_type !== "exact" && match_type !== "prefix" && match_type !== "regex") continue;
|
|
107
|
+
out.push({ pattern, match_type });
|
|
108
|
+
}
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
function parseBootstrapInactivePages(value) {
|
|
112
|
+
if (!Array.isArray(value)) return [];
|
|
113
|
+
const out = [];
|
|
114
|
+
for (const row of value) {
|
|
115
|
+
if (typeof row === "string") {
|
|
116
|
+
const pagePath2 = row.trim();
|
|
117
|
+
if (pagePath2 && pagePath2.startsWith("/")) out.push(pagePath2);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (!row || typeof row !== "object") continue;
|
|
121
|
+
const record = row;
|
|
122
|
+
const pagePath = typeof record.page_path === "string" ? record.page_path.trim() : "";
|
|
123
|
+
if (!pagePath || !pagePath.startsWith("/")) continue;
|
|
124
|
+
out.push(pagePath);
|
|
125
|
+
}
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// src/utils/logger.ts
|
|
130
|
+
function isDebugEnabled() {
|
|
131
|
+
if (typeof globalThis === "undefined") return false;
|
|
132
|
+
const value = globalThis.__lovalingoDebug;
|
|
133
|
+
if (value === true || value === "true" || value === 1) return true;
|
|
134
|
+
try {
|
|
135
|
+
const params = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : null;
|
|
136
|
+
const query = params?.get("lovalingoDebug") || params?.get("lovalingo_debug") || "";
|
|
137
|
+
if (query === "1" || query === "true") return true;
|
|
138
|
+
} catch {
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
const stored = typeof window !== "undefined" ? window.localStorage?.getItem("Lovalingo_debug") : null;
|
|
142
|
+
if (stored === "1" || stored === "true") return true;
|
|
143
|
+
} catch {
|
|
144
|
+
}
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
function logDebug(...args) {
|
|
148
|
+
if (!isDebugEnabled()) return;
|
|
149
|
+
console.log(...args);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// src/components/LangRouter.tsx
|
|
153
|
+
function NavigateExporter({ navigateRef }) {
|
|
154
|
+
const navigate = (0, import_react_router_dom.useNavigate)();
|
|
155
|
+
(0, import_react3.useEffect)(() => {
|
|
156
|
+
if (navigateRef) {
|
|
157
|
+
navigateRef.current = navigate;
|
|
158
|
+
}
|
|
159
|
+
}, [navigate, navigateRef]);
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
function LangGuard({
|
|
163
|
+
lang,
|
|
164
|
+
nonLocalizedPaths,
|
|
165
|
+
defaultLang
|
|
166
|
+
}) {
|
|
167
|
+
const location = (0, import_react_router_dom.useLocation)();
|
|
168
|
+
const prefix = `/${lang}`;
|
|
169
|
+
const restPath = location.pathname.startsWith(prefix) ? location.pathname.slice(prefix.length) || "/" : location.pathname;
|
|
170
|
+
if (isNonLocalizedPath(restPath, nonLocalizedPaths)) {
|
|
171
|
+
const nextPath = `${restPath}${location.search}${location.hash}`;
|
|
172
|
+
return /* @__PURE__ */ import_react3.default.createElement(import_react_router_dom.Navigate, { to: nextPath, replace: true });
|
|
173
|
+
}
|
|
174
|
+
return /* @__PURE__ */ import_react3.default.createElement(LangContext.Provider, { value: lang }, /* @__PURE__ */ import_react3.default.createElement(import_react_router_dom.Outlet, { context: { lang } }));
|
|
175
|
+
}
|
|
176
|
+
function RedirectToDefaultLang({
|
|
177
|
+
defaultLang,
|
|
178
|
+
children,
|
|
179
|
+
nonLocalizedPaths,
|
|
180
|
+
routingStatus
|
|
181
|
+
}) {
|
|
182
|
+
const location = (0, import_react_router_dom.useLocation)();
|
|
183
|
+
const navigate = (0, import_react_router_dom.useNavigate)();
|
|
184
|
+
const shouldSkip = isNonLocalizedPath(location.pathname, nonLocalizedPaths);
|
|
185
|
+
(0, import_react3.useEffect)(() => {
|
|
186
|
+
if (shouldSkip) return;
|
|
187
|
+
if (routingStatus === "loading") return;
|
|
188
|
+
const nextPath = location.pathname === "/" || location.pathname === "" ? `/${defaultLang}${location.search}${location.hash}` : `/${defaultLang}${location.pathname}${location.search}${location.hash}`;
|
|
189
|
+
const current = `${location.pathname}${location.search}${location.hash}`;
|
|
190
|
+
if (nextPath === current) return;
|
|
191
|
+
navigate(nextPath, { replace: true });
|
|
192
|
+
}, [defaultLang, location.hash, location.pathname, location.search, navigate, routingStatus, shouldSkip]);
|
|
193
|
+
return /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, children);
|
|
194
|
+
}
|
|
195
|
+
function LangRouter({ children, defaultLang, langs, navigateRef, apiBase, apiKey, publicAnonKey }) {
|
|
196
|
+
const metaKey = typeof document !== "undefined" ? document.querySelector('meta[name="lovalingo-public-anon-key"]')?.content?.trim() || "" : "";
|
|
197
|
+
const globals = globalThis;
|
|
198
|
+
const resolvedApiKey = (typeof apiKey === "string" && apiKey.trim().length > 0 ? apiKey : typeof publicAnonKey === "string" && publicAnonKey.trim().length > 0 ? publicAnonKey : globals.__LOVALINGO_PUBLIC_ANON_KEY__ || globals.__LOVALINGO_API_KEY__ || metaKey || "").trim();
|
|
199
|
+
const resolvedApiBase = typeof apiBase === "string" && apiBase.trim().length > 0 ? apiBase.trim() : "https://cdn.lovalingo.com";
|
|
200
|
+
const nonLocalizedStorageKey = (0, import_react3.useMemo)(
|
|
201
|
+
() => `Lovalingo_non_localized_paths:${resolvedApiKey || "anonymous"}`,
|
|
202
|
+
[resolvedApiKey]
|
|
203
|
+
);
|
|
204
|
+
const inactivePagesStorageKey = (0, import_react3.useMemo)(
|
|
205
|
+
() => `Lovalingo_inactive_pages:${resolvedApiKey || "anonymous"}`,
|
|
206
|
+
[resolvedApiKey]
|
|
207
|
+
);
|
|
208
|
+
const [nonLocalizedPaths, setNonLocalizedPaths] = (0, import_react3.useState)(() => {
|
|
209
|
+
if (typeof window === "undefined") return [];
|
|
210
|
+
if (!resolvedApiKey) return [];
|
|
211
|
+
try {
|
|
212
|
+
const raw = localStorage.getItem(nonLocalizedStorageKey);
|
|
213
|
+
if (!raw) return [];
|
|
214
|
+
const parsed = JSON.parse(raw);
|
|
215
|
+
return parseBootstrapNonLocalizedPaths(parsed);
|
|
216
|
+
} catch {
|
|
217
|
+
return [];
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
const [inactivePages, setInactivePages] = (0, import_react3.useState)(() => {
|
|
221
|
+
if (typeof window === "undefined") return [];
|
|
222
|
+
if (!resolvedApiKey) return [];
|
|
223
|
+
try {
|
|
224
|
+
const raw = localStorage.getItem(inactivePagesStorageKey);
|
|
225
|
+
if (!raw) return [];
|
|
226
|
+
const parsed = JSON.parse(raw);
|
|
227
|
+
return parseBootstrapInactivePages(parsed);
|
|
228
|
+
} catch {
|
|
229
|
+
return [];
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
const [routingStatus, setRoutingStatus] = (0, import_react3.useState)(() => {
|
|
233
|
+
if (!resolvedApiKey) return "unknown";
|
|
234
|
+
return nonLocalizedPaths.length > 0 || inactivePages.length > 0 ? "ready" : "loading";
|
|
235
|
+
});
|
|
236
|
+
const fetchRoutingConfig = (0, import_react3.useCallback)(async () => {
|
|
237
|
+
if (typeof window === "undefined") return;
|
|
238
|
+
if (!resolvedApiKey) return;
|
|
239
|
+
const pathParam = window.location.pathname + window.location.search;
|
|
240
|
+
const requestUrl = `${resolvedApiBase}/functions/v1/bootstrap?key=${encodeURIComponent(resolvedApiKey)}&locale=${encodeURIComponent(defaultLang)}&path=${encodeURIComponent(pathParam)}`;
|
|
241
|
+
const response = await fetch(requestUrl);
|
|
242
|
+
const resolvedResponse = response.status === 304 ? await fetch(requestUrl, { cache: "force-cache" }) : response;
|
|
243
|
+
if (!resolvedResponse.ok) throw new Error(`bootstrap HTTP ${resolvedResponse.status}`);
|
|
244
|
+
const data = await resolvedResponse.json();
|
|
245
|
+
const record = data || {};
|
|
246
|
+
return {
|
|
247
|
+
nonLocalizedPaths: parseBootstrapNonLocalizedPaths(record["non_localized_paths"]),
|
|
248
|
+
inactivePages: parseBootstrapInactivePages(record["inactive_pages"])
|
|
249
|
+
};
|
|
250
|
+
}, [defaultLang, resolvedApiBase, resolvedApiKey]);
|
|
251
|
+
(0, import_react3.useEffect)(() => {
|
|
252
|
+
let cancelled = false;
|
|
253
|
+
void (async () => {
|
|
254
|
+
if (!resolvedApiKey) return;
|
|
255
|
+
setRoutingStatus((prev) => prev === "ready" ? prev : "loading");
|
|
256
|
+
try {
|
|
257
|
+
const next = await fetchRoutingConfig();
|
|
258
|
+
if (cancelled || !next) return;
|
|
259
|
+
setNonLocalizedPaths(next.nonLocalizedPaths);
|
|
260
|
+
setInactivePages(next.inactivePages);
|
|
261
|
+
setRoutingStatus("ready");
|
|
262
|
+
try {
|
|
263
|
+
localStorage.setItem(nonLocalizedStorageKey, JSON.stringify(next.nonLocalizedPaths));
|
|
264
|
+
localStorage.setItem(inactivePagesStorageKey, JSON.stringify(next.inactivePages));
|
|
265
|
+
} catch {
|
|
266
|
+
}
|
|
267
|
+
} catch (err) {
|
|
268
|
+
if (cancelled) return;
|
|
269
|
+
setRoutingStatus("error");
|
|
270
|
+
logDebug("[Lovalingo] Failed to fetch routing config:", err);
|
|
271
|
+
}
|
|
272
|
+
})();
|
|
273
|
+
return () => {
|
|
274
|
+
cancelled = true;
|
|
275
|
+
};
|
|
276
|
+
}, [fetchRoutingConfig, inactivePagesStorageKey, nonLocalizedStorageKey, resolvedApiKey]);
|
|
277
|
+
return /* @__PURE__ */ import_react3.default.createElement(import_react_router_dom.BrowserRouter, null, /* @__PURE__ */ import_react3.default.createElement(NavigateExporter, { navigateRef }), /* @__PURE__ */ import_react3.default.createElement(LangRoutingContext.Provider, { value: { defaultLang, nonLocalizedPaths, inactivePages, status: routingStatus } }, /* @__PURE__ */ import_react3.default.createElement(import_react_router_dom.Routes, null, langs.map((lang) => /* @__PURE__ */ import_react3.default.createElement(
|
|
278
|
+
import_react_router_dom.Route,
|
|
279
|
+
{
|
|
280
|
+
key: lang,
|
|
281
|
+
path: `${lang}/*`,
|
|
282
|
+
element: /* @__PURE__ */ import_react3.default.createElement(LangGuard, { lang, nonLocalizedPaths, defaultLang })
|
|
283
|
+
},
|
|
284
|
+
/* @__PURE__ */ import_react3.default.createElement(import_react_router_dom.Route, { index: true, element: /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, children) }),
|
|
285
|
+
/* @__PURE__ */ import_react3.default.createElement(import_react_router_dom.Route, { path: "*", element: /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, children) })
|
|
286
|
+
)), /* @__PURE__ */ import_react3.default.createElement(
|
|
287
|
+
import_react_router_dom.Route,
|
|
288
|
+
{
|
|
289
|
+
path: "*",
|
|
290
|
+
element: /* @__PURE__ */ import_react3.default.createElement(
|
|
291
|
+
RedirectToDefaultLang,
|
|
292
|
+
{
|
|
293
|
+
defaultLang,
|
|
294
|
+
nonLocalizedPaths,
|
|
295
|
+
routingStatus
|
|
296
|
+
},
|
|
297
|
+
children
|
|
298
|
+
)
|
|
299
|
+
}
|
|
300
|
+
))));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// src/components/LangLink.tsx
|
|
304
|
+
var import_react5 = __toESM(require("react"));
|
|
305
|
+
var import_react_router_dom3 = require("react-router-dom");
|
|
306
|
+
|
|
307
|
+
// src/hooks/useLang.ts
|
|
308
|
+
var import_react_router_dom2 = require("react-router-dom");
|
|
309
|
+
var import_react4 = require("react");
|
|
310
|
+
function useLang() {
|
|
311
|
+
const ctxLang = (0, import_react4.useContext)(LangContext);
|
|
312
|
+
const { lang } = (0, import_react_router_dom2.useParams)();
|
|
313
|
+
return ctxLang ?? lang ?? "en";
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// src/components/LangLink.tsx
|
|
317
|
+
var import_react6 = require("react");
|
|
318
|
+
function LangLink({ to, ...props }) {
|
|
319
|
+
const lang = useLang();
|
|
320
|
+
const routing = (0, import_react6.useContext)(LangRoutingContext);
|
|
321
|
+
const langTo = typeof to === "string" ? (() => {
|
|
322
|
+
const trimmed = (to || "").toString().trim();
|
|
323
|
+
const normalized = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
324
|
+
return isNonLocalizedPath(normalized, routing.nonLocalizedPaths) ? normalized : `/${lang}${normalized}`;
|
|
325
|
+
})() : to;
|
|
326
|
+
return /* @__PURE__ */ import_react5.default.createElement(import_react_router_dom3.Link, { ...props, to: langTo });
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// src/hooks/useLangNavigate.ts
|
|
330
|
+
var import_react_router_dom4 = require("react-router-dom");
|
|
331
|
+
var import_react7 = require("react");
|
|
332
|
+
function useLangNavigate() {
|
|
333
|
+
const navigate = (0, import_react_router_dom4.useNavigate)();
|
|
334
|
+
const lang = useLang();
|
|
335
|
+
const routing = (0, import_react7.useContext)(LangRoutingContext);
|
|
336
|
+
return (0, import_react7.useCallback)(
|
|
337
|
+
(path, options) => {
|
|
338
|
+
const trimmed = (path || "").toString().trim();
|
|
339
|
+
if (!trimmed) return;
|
|
340
|
+
const normalized = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
341
|
+
const fullPath = isNonLocalizedPath(normalized, routing.nonLocalizedPaths) ? normalized : `/${lang}${normalized}`;
|
|
342
|
+
navigate(fullPath, options);
|
|
343
|
+
},
|
|
344
|
+
[lang, navigate, routing.nonLocalizedPaths]
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
348
|
+
0 && (module.exports = {
|
|
349
|
+
LangLink,
|
|
350
|
+
LangRouter,
|
|
351
|
+
useLang,
|
|
352
|
+
useLangNavigate
|
|
353
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
type NonLocalizedPathRule = {
|
|
2
|
+
pattern: string;
|
|
3
|
+
match_type: "exact" | "prefix" | "regex";
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
type RewriteArgs = {
|
|
7
|
+
url: URL;
|
|
8
|
+
};
|
|
9
|
+
type LovalingoTanStackRewrite = {
|
|
10
|
+
input: (args: RewriteArgs) => URL | string | undefined;
|
|
11
|
+
output: (args: RewriteArgs) => URL | string | undefined;
|
|
12
|
+
};
|
|
13
|
+
type LovalingoTanStackRewriteOptions = {
|
|
14
|
+
defaultLocale: string;
|
|
15
|
+
locales: string[];
|
|
16
|
+
prefixDefaultLocale?: boolean;
|
|
17
|
+
nonLocalizedPaths?: NonLocalizedPathRule[];
|
|
18
|
+
getLocale?: () => string | undefined;
|
|
19
|
+
};
|
|
20
|
+
declare function createLovalingoTanStackRewrite({ defaultLocale, locales, prefixDefaultLocale, nonLocalizedPaths, getLocale, }: LovalingoTanStackRewriteOptions): LovalingoTanStackRewrite;
|
|
21
|
+
|
|
22
|
+
export { type LovalingoTanStackRewrite, type LovalingoTanStackRewriteOptions, type NonLocalizedPathRule, createLovalingoTanStackRewrite };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
type NonLocalizedPathRule = {
|
|
2
|
+
pattern: string;
|
|
3
|
+
match_type: "exact" | "prefix" | "regex";
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
type RewriteArgs = {
|
|
7
|
+
url: URL;
|
|
8
|
+
};
|
|
9
|
+
type LovalingoTanStackRewrite = {
|
|
10
|
+
input: (args: RewriteArgs) => URL | string | undefined;
|
|
11
|
+
output: (args: RewriteArgs) => URL | string | undefined;
|
|
12
|
+
};
|
|
13
|
+
type LovalingoTanStackRewriteOptions = {
|
|
14
|
+
defaultLocale: string;
|
|
15
|
+
locales: string[];
|
|
16
|
+
prefixDefaultLocale?: boolean;
|
|
17
|
+
nonLocalizedPaths?: NonLocalizedPathRule[];
|
|
18
|
+
getLocale?: () => string | undefined;
|
|
19
|
+
};
|
|
20
|
+
declare function createLovalingoTanStackRewrite({ defaultLocale, locales, prefixDefaultLocale, nonLocalizedPaths, getLocale, }: LovalingoTanStackRewriteOptions): LovalingoTanStackRewrite;
|
|
21
|
+
|
|
22
|
+
export { type LovalingoTanStackRewrite, type LovalingoTanStackRewriteOptions, type NonLocalizedPathRule, createLovalingoTanStackRewrite };
|