@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
|
|
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<
|
|
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
|
|
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):
|
|
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.
|
|
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.
|
|
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"
|