@lovalingo/lovalingo 0.0.27 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,18 @@
1
- # @lovalingo/lovalingo — Best Weglot & i18n alternative for Vibe Coders, Lovable, v0, Emergent & more
1
+ # @lovalingo/lovalingo
2
2
 
3
- Seamless website translation for React (React Router) and Next.js with **zero‑flash rendering**, **automatic language routing**, and **SEO signals (canonical + hreflang)** built for fast iteration in AI/vibe‑coding workflows.
3
+ Lovalingo is a translation runtime for React (React Router) and Next.js that loads **pre-built artifacts** (JSON bundles + DOM rules) from the Lovalingo backend and applies them with **zero-flash**.
4
4
 
5
- If you ship with Lovable, v0, Emergent, Vite, Claude Code or similar tools, Lovalingo is the fastest way to production‑grade i18n without Weglot overhead.
5
+ It does **not** generate translations in the browser.
6
+
7
+ ## How it works (high level)
8
+
9
+ 1. Your app renders normally (source language).
10
+ 2. Lovalingo loads the current locale’s bundle from the backend.
11
+ 3. The runtime mutates the DOM before paint (and keeps up with route changes + dynamic content).
12
+ 4. Optional: Lovalingo fetches DOM rules (CSS/JS/DOM patches) to fix edge cases (hidden UI, wrapping, etc.).
13
+ 5. Optional SEO: Lovalingo updates `<head>` (canonical + hreflang + basic meta) using `seo-bundle`.
14
+
15
+ All artifacts are produced server-side by the pipeline (render → audit → deterministic translate → optional fix loop).
6
16
 
7
17
  ## Installation
8
18
 
@@ -10,106 +20,75 @@ If you ship with Lovable, v0, Emergent, Vite, Claude Code or similar tools, Lova
10
20
  npm install @lovalingo/lovalingo react-router-dom
11
21
  ```
12
22
 
13
- ## Quick Start
23
+ ## React Router
14
24
 
15
- ### Option 1: Path Mode (Recommended - Automatic Language URLs)
16
-
17
- **One-line setup** that automatically handles language routing like `/en/pricing`, `/fr/pricing`, `/de/pricing`:
25
+ ### Query mode (default)
18
26
 
19
27
  ```tsx
20
- import { LangRouter, LovalingoProvider } from '@lovalingo/lovalingo';
21
- import { Routes, Route } from 'react-router-dom';
22
- import { useRef } from 'react';
23
-
24
- function App() {
25
- const navigateRef = useRef();
28
+ import { BrowserRouter } from "react-router-dom";
29
+ import { LovalingoProvider } from "@lovalingo/lovalingo";
26
30
 
31
+ export function App() {
27
32
  return (
28
- <LangRouter defaultLang="en" langs={['en', 'fr', 'de', 'es']} navigateRef={navigateRef}>
33
+ <BrowserRouter>
29
34
  <LovalingoProvider
30
35
  publicAnonKey="aix_your_public_anon_key"
31
36
  defaultLocale="en"
32
- locales={['en', 'fr', 'de', 'es']}
33
- routing="path"
34
- navigateRef={navigateRef}
37
+ locales={["en", "de", "fr"]}
38
+ routing="query"
35
39
  >
36
- <Routes>
37
- {/* No language prefix needed! */}
38
- <Route path="/" element={<Home />} />
39
- <Route path="home" element={<Home />} />
40
- <Route path="pricing" element={<Pricing />} />
41
- <Route path="about" element={<About />} />
42
- </Routes>
40
+ <YourApp />
43
41
  </LovalingoProvider>
44
- </LangRouter>
42
+ </BrowserRouter>
45
43
  );
46
44
  }
47
45
  ```
48
46
 
49
- **Important:** Pass the same `navigateRef` to both `<LangRouter>` and `<LovalingoProvider>` for proper URL synchronization.
50
-
51
- **Common error (React Router v6):** If you see `LovalingoProvider is not a <Route> component`, you’re either:
52
- - on an older `@lovalingo/lovalingo` version (upgrade), or
53
- - you accidentally placed `<LovalingoProvider>` directly inside `<Routes>`.
47
+ URLs look like: `/pricing?t=de`.
54
48
 
55
- Correct:
56
- ```tsx
57
- <LovalingoProvider ...>
58
- <Routes>...</Routes>
59
- </LovalingoProvider>
60
- ```
49
+ ### Path mode (SEO-friendly URLs)
61
50
 
62
- Incorrect:
63
51
  ```tsx
64
- <Routes>
65
- <LovalingoProvider ... />
66
- </Routes>
67
- ```
68
-
69
- URLs automatically work as:
70
- - `/en/`, `/en/home`, `/en/pricing`, `/en/about`
71
- - `/fr/`, `/fr/home`, `/fr/pricing`, `/fr/about`
72
- - `/de/`, `/de/home`, `/de/pricing`, `/de/about`
73
-
74
- ### Option 2: Query Mode (Simple - Query Parameters)
52
+ import { useRef } from "react";
53
+ import { Routes, Route } from "react-router-dom";
54
+ import { LangRouter, LovalingoProvider } from "@lovalingo/lovalingo";
75
55
 
76
- Use query parameters like `/pricing?t=fr`:
56
+ export function App() {
57
+ const navigateRef = useRef<((path: string) => void) | undefined>(undefined);
77
58
 
78
- ```tsx
79
- import { LovalingoProvider } from '@lovalingo/lovalingo';
80
- import { BrowserRouter } from 'react-router-dom';
81
-
82
- function App() {
83
59
  return (
84
- <BrowserRouter>
60
+ <LangRouter defaultLang="en" langs={["en", "de", "fr"]} navigateRef={navigateRef}>
85
61
  <LovalingoProvider
86
62
  publicAnonKey="aix_your_public_anon_key"
87
63
  defaultLocale="en"
88
- locales={['en', 'de', 'fr', 'es']}
89
- routing="query"
64
+ locales={["en", "de", "fr"]}
65
+ routing="path"
66
+ navigateRef={navigateRef}
90
67
  >
91
- <YourApp />
68
+ <Routes>
69
+ <Route path="/" element={<Home />} />
70
+ <Route path="pricing" element={<Pricing />} />
71
+ <Route path="about" element={<About />} />
72
+ </Routes>
92
73
  </LovalingoProvider>
93
- </BrowserRouter>
74
+ </LangRouter>
94
75
  );
95
76
  }
96
77
  ```
97
78
 
98
- ### Next.js
79
+ URLs look like: `/de/pricing`.
80
+
81
+ ## Next.js (App Router)
99
82
 
100
83
  ```tsx
101
84
  // app/layout.tsx
102
- import { LovalingoProvider } from '@lovalingo/lovalingo';
85
+ import { LovalingoProvider } from "@lovalingo/lovalingo";
103
86
 
104
- export default function RootLayout({ children }) {
87
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
105
88
  return (
106
89
  <html>
107
90
  <body>
108
- <LovalingoProvider
109
- publicAnonKey="aix_your_public_anon_key"
110
- defaultLocale="en"
111
- locales={['en', 'de', 'fr', 'es']}
112
- >
91
+ <LovalingoProvider publicAnonKey="aix_your_public_anon_key" defaultLocale="en" locales={["en", "de", "fr"]}>
113
92
  {children}
114
93
  </LovalingoProvider>
115
94
  </body>
@@ -118,121 +97,27 @@ export default function RootLayout({ children }) {
118
97
  }
119
98
  ```
120
99
 
121
- ## Configuration
122
-
123
- ```tsx
124
- <LovalingoProvider
125
- publicAnonKey="aix_xxx" // Required: Your Lovalingo Public Anon Key (safe to expose)
126
- defaultLocale="en" // Required: Source language
127
- locales={['en', 'de', 'fr']} // Required: Supported languages
128
- apiBase="https://..." // Optional: Custom API endpoint
129
- routing="query" // Optional: 'query' | 'path' (default: 'query')
130
- autoPrefixLinks={true} // Optional (path mode): keep locale when the app renders absolute links like "/pricing"
131
- switcherPosition="bottom-right" // Optional: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'
132
- switcherOffsetY={20} // Optional: Vertical offset in pixels
133
- editMode={false} // Optional: Enable edit mode
134
- editKey="KeyE" // Optional: Keyboard shortcut for edit mode
135
- mode="dom" // Optional: 'dom' | 'context' (default: 'dom')
136
- pathNormalization={{ enabled: true }}// Optional: normalize paths for stable translation keys (default: enabled)
137
- seo={true} // Optional: auto canonical + hreflang + sitemap link (default: true)
138
- sitemap={true} // Optional: auto-inject sitemap link (default: true)
139
- >
140
- {children}
141
- </LovalingoProvider>
142
- ```
143
-
144
- ### Optional: Inject via `index.html`
145
-
146
- If your tooling prefers you to avoid hardcoding the key inside JSX, you can inject it at runtime:
147
-
148
- ```html
149
- <meta name="lovalingo-public-anon-key" content="aix_xxx" />
150
- <script>
151
- window.__LOVALINGO_PUBLIC_ANON_KEY__ = "aix_xxx";
152
- </script>
153
- ```
154
-
155
- Then you may omit `publicAnonKey` and Lovalingo will read it from the meta tag or `window.__LOVALINGO_PUBLIC_ANON_KEY__`.
156
-
157
- ### Routing Modes
158
-
159
- - **`query`** (default): Language in query parameter `/pricing?t=fr`
160
- - Use with standard React Router setup
161
- - No URL structure changes needed
162
-
163
- - **`path`**: Language in URL path `/fr/pricing`
164
- - Use with `<LangRouter>` wrapper
165
- - Automatic language routing
166
- - SEO-optimized URLs
167
- - Non-localized by default: `/auth`, `/login`, `/signup` (no `/:lang/` prefix)
168
- - See [PATH_EXAMPLES.md](./PATH_EXAMPLES.md) for detailed examples
100
+ ## SEO (canonical + hreflang + meta)
169
101
 
170
- ## Path Mode Helpers (v0.0.x+)
171
-
172
- ### LangLink - Language-Aware Links
102
+ Enabled by default. Disable if you already manage `<head>` yourself:
173
103
 
174
104
  ```tsx
175
- import { LangLink } from '@lovalingo/lovalingo';
176
-
177
- function Navigation() {
178
- return (
179
- <nav>
180
- {/* Automatically becomes /en/pricing or /fr/pricing */}
181
- <LangLink to="pricing">Pricing</LangLink>
182
- <LangLink to="about">About</LangLink>
183
- </nav>
184
- );
185
- }
105
+ <LovalingoProvider seo={false} ... />
186
106
  ```
187
107
 
188
- ### useLang - Get Current Language
108
+ ## Sitemap link tag
189
109
 
190
- ```tsx
191
- import { useLang } from '@lovalingo/lovalingo';
192
-
193
- function MyComponent() {
194
- const lang = useLang(); // 'en', 'fr', 'de', etc.
195
- return <div>Current language: {lang}</div>;
196
- }
197
- ```
198
-
199
- ### useLangNavigate - Programmatic Navigation
110
+ By default Lovalingo injects `<link rel="sitemap" href="/sitemap.xml">` for discovery. Disable it:
200
111
 
201
112
  ```tsx
202
- import { useLangNavigate } from '@lovalingo/lovalingo';
203
-
204
- function MyComponent() {
205
- const navigate = useLangNavigate();
206
-
207
- const goToPricing = () => {
208
- navigate('pricing'); // Goes to /en/pricing or /fr/pricing automatically
209
- };
210
-
211
- return <button onClick={goToPricing}>View Pricing</button>;
212
- }
113
+ <LovalingoProvider sitemap={false} ... />
213
114
  ```
214
115
 
215
- ## Core Hooks
116
+ You still need to serve `/sitemap.xml` on your own domain (recommended: reverse-proxy to Lovalingo’s `generate-sitemap` endpoint).
216
117
 
217
- ### useLovalingo
218
-
219
- Access locale state and switching:
220
-
221
- ```tsx
222
- import { useLovalingo } from '@lovalingo/lovalingo';
223
-
224
- function MyComponent() {
225
- const { locale, setLocale, isLoading, config } = useLovalingo();
226
-
227
- return (
228
- <button onClick={() => setLocale('de')}>
229
- Switch to German
230
- </button>
231
- );
232
- }
233
- ```
118
+ ## License
234
119
 
235
- ### useLovalingoTranslate
120
+ Commercial license (not open source). See `react-package/LICENSE`.
236
121
 
237
122
  Manual translation control:
238
123
 
@@ -290,6 +175,23 @@ function MyComponent() {
290
175
  - ✅ RTL ready: automatically sets `<html dir="rtl">` for `ar/he/fa/ur`
291
176
  - ✅ Optional Context Mode: `<AutoTranslate>` with hash-based caching for React text nodes
292
177
 
178
+ ## Language Switcher
179
+
180
+ Lovalingo includes a floating language switcher.
181
+
182
+ ```tsx
183
+ <LovalingoProvider
184
+ publicAnonKey="aix_xxx"
185
+ defaultLocale="en"
186
+ locales={["en", "de", "fr"]}
187
+ switcherPosition="bottom-right"
188
+ switcherOffsetY={20}
189
+ switcherTheme="light" // "dark" | "light" (default: "dark")
190
+ >
191
+ <App />
192
+ </LovalingoProvider>
193
+ ```
194
+
293
195
  ## SEO (Canonical + hreflang)
294
196
 
295
197
  Lovalingo can keep `<head>` SEO signals in sync with the active locale:
@@ -6,22 +6,5 @@ interface LovalingoProviderProps extends LovalingoConfig {
6
6
  seo?: boolean;
7
7
  navigateRef?: React.MutableRefObject<((path: string) => void) | undefined>;
8
8
  }
9
- type LovalingoSeleniumBridge = {
10
- getStatus: () => {
11
- mode: LovalingoConfig["mode"];
12
- locale: string;
13
- defaultLocale: string;
14
- path: string;
15
- missed: number;
16
- };
17
- flushMisses: () => Promise<{
18
- reported: number;
19
- locale: string;
20
- path: string;
21
- }>;
22
- };
23
- declare global {
24
- var __LOVALINGO_SELENIUM__: LovalingoSeleniumBridge | undefined;
25
- }
26
9
  export declare const LovalingoProvider: React.FC<LovalingoProviderProps>;
27
10
  export {};