@lingo.dev/compiler 0.1.1 → 0.1.2

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
@@ -13,7 +13,10 @@ automatically transforms React components to inject translation calls.
13
13
  - **Opt-in or automatic** - Configure whether to require `'use i18n'` directive or transform all files
14
14
  - **Multi-bundler support** - Works with Vite, Webpack and Next.js (both Webpack and Turbopack builds)
15
15
  - **Translation server** - On-demand translation generation during development
16
- - **AI-powered translations** - Support for multiple LLM providers and Lingo.dev Engine
16
+ - **AI-powered translations** - Support for multiple LLM providers (OpenAI, Anthropic, Google Gemini, Groq, Mistral, OpenRouter, Ollama) and Lingo.dev Engine
17
+ - **Manual overrides** - Override AI translations for specific locales using `data-lingo-override` attribute
18
+ - **Custom locale resolvers** - Provide your own locale detection and persistence logic
19
+ - **Automatic pluralization** - Detects and converts messages to ICU MessageFormat
17
20
 
18
21
  ## Getting started
19
22
 
@@ -58,7 +61,7 @@ Install the package - `pnpm install @lingo.dev/compiler`
58
61
  }
59
62
  ```
60
63
 
61
- See `demo/vite-react-spa` for the working example
64
+ See `demo/new-compiler-vite-react-spa` for the working example
62
65
 
63
66
  ### Next.js
64
67
 
@@ -99,6 +102,274 @@ See `demo/vite-react-spa` for the working example
99
102
  }
100
103
  ```
101
104
 
105
+ See `demo/new-compiler-next16` for the working example
106
+
107
+ ## Configuration Options
108
+
109
+ ### Core Configuration
110
+
111
+ | Option | Type | Default | Description |
112
+ |--------|------|---------|-------------|
113
+ | `sourceRoot` | `string` | `"src"` | Root directory of the source code |
114
+ | `lingoDir` | `string` | `"lingo"` | Directory for lingo files (`.lingo/`) |
115
+ | `sourceLocale` | `LocaleCode` | **(required)** | Source locale (e.g., `"en"`, `"en-US"`) |
116
+ | `targetLocales` | `LocaleCode[]` | **(required)** | Target locales to translate to |
117
+ | `useDirective` | `boolean` | `false` | Whether to require `'use i18n'` directive |
118
+ | `models` | `string \| Record<string, string>` | `"lingo.dev"` | Model configuration (see below) |
119
+ | `prompt` | `string` | `undefined` | Custom translation prompt |
120
+ | `buildMode` | `"translate" \| "cache-only"` | `"translate"` | Build mode (see below) |
121
+
122
+ ### Development Configuration
123
+
124
+ Configure development-specific behavior via the `dev` option:
125
+
126
+ ```ts
127
+ {
128
+ dev: {
129
+ // Use pseudotranslator (fake translations) instead of real AI
130
+ usePseudotranslator: boolean; // default: false
131
+
132
+ // Starting port for translation server
133
+ translationServerStartPort: number; // default: 60000
134
+
135
+ // Custom translation server URL (advanced)
136
+ translationServerUrl?: string;
137
+ }
138
+ }
139
+ ```
140
+
141
+ ### Locale Persistence
142
+
143
+ Configure how locale changes are persisted:
144
+
145
+ ```ts
146
+ {
147
+ localePersistence: {
148
+ type: "cookie",
149
+ config: {
150
+ name: string; // default: "locale"
151
+ maxAge: number; // default: 31536000 (1 year)
152
+ }
153
+ }
154
+ }
155
+ ```
156
+
157
+ ### Pluralization
158
+
159
+ Configure automatic pluralization detection:
160
+
161
+ ```ts
162
+ {
163
+ pluralization: {
164
+ enabled: boolean; // default: true
165
+ model: string; // default: "groq:llama-3.1-8b-instant"
166
+ }
167
+ }
168
+ ```
169
+
170
+ ## Using LLMs for Translation
171
+
172
+ ### Lingo.dev Engine (Recommended)
173
+
174
+ The simplest way to get started is using Lingo.dev Engine:
175
+
176
+ ```ts
177
+ {
178
+ models: "lingo.dev"
179
+ }
180
+ ```
181
+
182
+ Set your API key in `.env`:
183
+
184
+ ```bash
185
+ LINGODOTDEV_API_KEY=your_api_key_here
186
+ ```
187
+
188
+ Get your API key at [lingo.dev](https://lingo.dev)
189
+
190
+ ### Direct LLM Providers
191
+
192
+ You can use any supported LLM provider directly. Configure using locale-pair mapping:
193
+
194
+ ```ts
195
+ {
196
+ models: {
197
+ // Specific locale pair
198
+ "en:es": "google:gemini-2.0-flash",
199
+
200
+ // Wildcard patterns
201
+ "*:de": "groq:llama3-8b-8192", // All translations to German
202
+ "en:*": "openai:gpt-4o", // All translations from English
203
+ "*:*": "anthropic:claude-3-5-sonnet" // Fallback for all other pairs
204
+ }
205
+ }
206
+ ```
207
+
208
+ **Supported Providers:**
209
+
210
+ | Provider | Model String Format | Environment Variable | Get API Key |
211
+ |----------|---------------------|---------------------|-------------|
212
+ | **OpenAI** | `openai:gpt-4o` | `OPENAI_API_KEY` | [platform.openai.com](https://platform.openai.com/account/api-keys) |
213
+ | **Anthropic** | `anthropic:claude-3-5-sonnet` | `ANTHROPIC_API_KEY` | [console.anthropic.com](https://console.anthropic.com/get-api-key) |
214
+ | **Google** | `google:gemini-2.0-flash` | `GOOGLE_API_KEY` | [ai.google.dev](https://ai.google.dev/) |
215
+ | **Groq** | `groq:llama3-8b-8192` | `GROQ_API_KEY` | [groq.com](https://groq.com) |
216
+ | **Mistral** | `mistral:mistral-large` | `MISTRAL_API_KEY` | [console.mistral.ai](https://console.mistral.ai) |
217
+ | **OpenRouter** | `openrouter:anthropic/claude-3.5-sonnet` | `OPENROUTER_API_KEY` | [openrouter.ai](https://openrouter.ai) |
218
+ | **Ollama** | `ollama:llama2` | *(none required)* | [ollama.com/download](https://ollama.com/download) |
219
+
220
+ **Example with multiple providers:**
221
+
222
+ ```ts
223
+ {
224
+ sourceLocale: "en",
225
+ targetLocales: ["es", "de", "fr", "ja"],
226
+ models: {
227
+ "en:es": "groq:llama3-8b-8192", // Fast & cheap for Spanish
228
+ "en:de": "google:gemini-2.0-flash", // Good for German
229
+ "*:*": "openai:gpt-4o" // High quality for everything else
230
+ }
231
+ }
232
+ ```
233
+
234
+ ### Custom Translation Prompts
235
+
236
+ Customize the translation prompt using placeholders:
237
+
238
+ ```ts
239
+ {
240
+ models: "lingo.dev",
241
+ prompt: "Translate from {SOURCE_LOCALE} to {TARGET_LOCALE}. Use a formal tone and preserve all technical terms."
242
+ }
243
+ ```
244
+
245
+ ## Manual Translation Overrides
246
+
247
+ Override AI-generated translations for specific text using the `data-lingo-override` attribute:
248
+
249
+ ```tsx
250
+ export function Welcome() {
251
+ return (
252
+ <div>
253
+ {/* Override translations for brand name */}
254
+ <h1 data-lingo-override={{ de: "Lingo.dev", fr: "Lingo.dev", es: "Lingo.dev" }}>
255
+ Lingo.dev
256
+ </h1>
257
+
258
+ {/* Override only specific locales */}
259
+ <p data-lingo-override={{ de: "Professionelle Übersetzung" }}>
260
+ Professional translation
261
+ </p>
262
+
263
+ {/* Works with rich text and interpolations */}
264
+ <p data-lingo-override={{
265
+ de: "Willkommen <strong0>{name}</strong0>",
266
+ fr: "Bienvenue <strong0>{name}</strong0>"
267
+ }}>
268
+ Welcome <strong>{name}</strong>
269
+ </p>
270
+ </div>
271
+ );
272
+ }
273
+ ```
274
+
275
+ The `data-lingo-override` attribute:
276
+ - Accepts an object with locale codes as keys
277
+ - Supports partial overrides (only specify locales you want to override)
278
+ - Is automatically removed from the final output
279
+ - Works with locale region codes (e.g., `en-US`, `en-GB`)
280
+ - Supports rich text with component placeholders (e.g., `<strong0>`)
281
+
282
+ **Use cases:**
283
+ - Brand names that shouldn't be translated
284
+ - Technical terms requiring specific translations
285
+ - Legal text requiring certified translations
286
+ - Marketing copy that needs human review
287
+
288
+ ## Build Modes
289
+
290
+ Control how translations are handled at build time:
291
+
292
+ ### `translate` (default)
293
+
294
+ Generate missing translations at build time using configured LLM:
295
+
296
+ ```ts
297
+ {
298
+ buildMode: "translate"
299
+ }
300
+ ```
301
+
302
+ - Generates translations for any missing entries
303
+ - Fails build if translation fails
304
+ - Best for: Development and CI pipelines with API keys
305
+
306
+ ### `cache-only`
307
+
308
+ Only use existing cached translations:
309
+
310
+ ```ts
311
+ {
312
+ buildMode: "cache-only"
313
+ }
314
+ ```
315
+
316
+ - No API calls made during build
317
+ - Fails build if translations are missing
318
+ - Best for: Production builds without API keys
319
+ - Requires translations to be pre-generated (during dev or in CI)
320
+
321
+ **Environment Variable Override:**
322
+
323
+ ```bash
324
+ LINGO_BUILD_MODE=cache-only npm run build
325
+ ```
326
+
327
+ **Recommended Workflow:**
328
+
329
+ 1. **Development**: Use `translate` mode with `usePseudotranslator: true`
330
+ 2. **CI**: Generate real translations with `buildMode: "translate"` and real API keys
331
+ 3. **Production Build**: Use `buildMode: "cache-only"` (no API keys needed)
332
+
333
+ ## Custom Locale Resolvers
334
+
335
+ Customize how locales are detected and persisted by providing custom resolver files:
336
+
337
+ ### Custom Server Locale Resolver
338
+
339
+ Create `.lingo/locale-resolver.server.ts` (Next.js):
340
+
341
+ ```ts
342
+ // Custom server-side locale detection
343
+ export async function getServerLocale(): Promise<string> {
344
+ // Your custom logic - e.g., from database, headers, etc.
345
+ const { headers } = await import('next/headers');
346
+ const headersList = await headers();
347
+ const acceptLanguage = headersList.get('accept-language');
348
+
349
+ // Parse and return locale
350
+ return acceptLanguage?.split(',')[0]?.split('-')[0] || 'en';
351
+ }
352
+ ```
353
+
354
+ ### Custom Client Locale Resolver
355
+
356
+ Create `.lingo/locale-resolver.client.ts`:
357
+
358
+ ```ts
359
+ // Custom client-side locale detection and persistence
360
+ export function getClientLocale(): string {
361
+ // Your custom logic - e.g., from localStorage, URL params, etc.
362
+ return localStorage.getItem('user-locale') || 'en';
363
+ }
364
+
365
+ export function persistLocale(locale: string): void {
366
+ localStorage.setItem('user-locale', locale);
367
+ // Optionally update URL, etc.
368
+ }
369
+ ```
370
+
371
+ If these files don't exist, the compiler uses the default cookie-based implementation.
372
+
102
373
  ## Development
103
374
 
104
375
  `pnpm install` from project root
@@ -1,12 +1,12 @@
1
1
  import { LingoProviderProps } from "../shared/LingoProvider.cjs";
2
- import * as react_jsx_runtime3 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime2 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/react/server/ServerLingoProvider.d.ts
5
5
  declare function LingoProvider({
6
6
  initialLocale,
7
7
  initialTranslations,
8
8
  ...rest
9
- }: LingoProviderProps): Promise<react_jsx_runtime3.JSX.Element>;
9
+ }: LingoProviderProps): Promise<react_jsx_runtime2.JSX.Element>;
10
10
  //#endregion
11
11
  export { LingoProvider };
12
12
  //# sourceMappingURL=ServerLingoProvider.d.cts.map
@@ -1,5 +1,5 @@
1
1
  import { LocaleCode } from "lingo.dev/spec";
2
- import * as react_jsx_runtime2 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime3 from "react/jsx-runtime";
3
3
  import { CSSProperties } from "react";
4
4
 
5
5
  //#region src/react/shared/LocaleSwitcher.d.ts
@@ -65,7 +65,7 @@ declare function LocaleSwitcher({
65
65
  style,
66
66
  className,
67
67
  showLoadingState
68
- }: LocaleSwitcherProps): react_jsx_runtime2.JSX.Element;
68
+ }: LocaleSwitcherProps): react_jsx_runtime3.JSX.Element;
69
69
  //#endregion
70
70
  export { LocaleSwitcher };
71
71
  //# sourceMappingURL=LocaleSwitcher.d.cts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lingo.dev/compiler",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Lingo.dev Compiler",
5
5
  "private": false,
6
6
  "repository": {
@@ -154,7 +154,7 @@
154
154
  "dotenv": "^17.2.3",
155
155
  "fast-xml-parser": "^5.3.3",
156
156
  "intl-messageformat": "^11.0.6",
157
- "lingo.dev": "^0.117.0",
157
+ "lingo.dev": "^0.117.21",
158
158
  "lodash": "^4.17.21",
159
159
  "proper-lockfile": "^4.1.2",
160
160
  "ws": "^8.18.3"