Skip to content

Commit 1adc476

Browse files
committed
WIP: make next workflow more transparent
1 parent 86463bf commit 1adc476

17 files changed

Lines changed: 362 additions & 578 deletions

cmp/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
### Development
2+
3+
`pnpm install` from project root
4+
`pnpm turbo dev --filter=@lingo.dev/compile` to compile and watch for compiler changes
5+
6+
Choose the demo you want to work with and run it from the corresponding folder.
7+
`tsdown` in compiler is configured to cleanup the output folder before compilation, which works fine with next, but vite
8+
seems to be dead every time and has to be restarted.

cmp/compiler/README.md

Lines changed: 16 additions & 252 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
1-
# @lingo.dev/\_compiler
1+
# @lingo.dev/compiler
22

33
Official Lingo.dev compiler with automatic translation support for React applications.
44

5-
This package provides plugins for multiple bundlers (Vite, Webpack, Rollup, esbuild) and a Next.js loader that automatically transforms React components to inject translation calls. It uses a hash-based metadata system to track translatable text across your application.
5+
This package provides plugins for multiple bundlers (Vite, Webpack, Rollup, esbuild) and a Next.js loader that
6+
automatically transforms React components to inject translation calls. It uses a hash-based metadata system to track
7+
translatable text across your application.
68

79
## Features
810

9-
- 🔄 **Automatic JSX text transformation** - Automatically detects and transforms translatable text in JSX
10-
- 📝 **Hash-based metadata** - Generates unique hashes for each translatable text based on content, component name, and file path
11-
- 🎯 **Opt-in or automatic** - Configure whether to require `'use i18n'` directive or transform all files
12-
- 🔌 **Multi-bundler support** - Works with Vite, Webpack, Rollup, esbuild, and Next.js
13-
- 🏗️ **Built on unplugin** - Unified plugin API across all bundlers
14-
- 📊 **Metadata tracking** - Maintains `.lingo/metadata.json` with all translatable content
15-
-**Translation server** - On-demand translation generation during development
16-
- 🌐 **AI-powered translations** - Support for multiple LLM providers and Lingo.dev Engine
11+
- **Automatic JSX text transformation** - Automatically detects and transforms translatable text in JSX
12+
- **Hash-based metadata** - Generates unique hashes for each translatable text based on content, component name, and
13+
file path
14+
- **Opt-in or automatic** - Configure whether to require `'use i18n'` directive or transform all files
15+
- **Multi-bundler support** - Works with Vite, Webpack, Rollup, esbuild, and Next.js
16+
- **Built on unplugin** - Unified plugin API across all bundlers
17+
- **Metadata tracking** - Maintains `.lingo/metadata.json` with all translatable content
18+
- **Translation server** - On-demand translation generation during development
19+
- **AI-powered translations** - Support for multiple LLM providers and Lingo.dev Engine
1720

1821
## Installation
1922

@@ -27,128 +30,11 @@ yarn add @lingo.dev/compiler
2730

2831
## Quick Start
2932

30-
### Vite
31-
32-
```ts
33-
// vite.config.ts
34-
import { defineConfig } from "vite";
35-
import { lingoCompilerPlugin } from "@lingo.dev/compiler/vite";
36-
37-
export default defineConfig({
38-
plugins: [
39-
lingoCompilerPlugin({
40-
sourceLocale: "en",
41-
targetLocales: ["es", "fr"],
42-
}),
43-
],
44-
});
45-
```
46-
47-
### Webpack
48-
49-
```js
50-
// webpack.config.js
51-
import { lingoCompilerPlugin } from "@lingo.dev/compiler/webpack";
52-
53-
export default {
54-
plugins: [
55-
lingoCompilerPlugin({
56-
sourceLocale: "en",
57-
targetLocales: ["es", "fr"],
58-
}),
59-
],
60-
};
61-
```
62-
63-
### Rollup
64-
65-
```js
66-
// rollup.config.js
67-
import { lingoCompilerPlugin } from "@lingo.dev/compiler/rollup";
68-
69-
export default {
70-
plugins: [
71-
lingoCompilerPlugin({
72-
sourceLocale: "en",
73-
targetLocales: ["es", "fr"],
74-
}),
75-
],
76-
};
77-
```
78-
79-
### esbuild
80-
81-
```js
82-
// build.js
83-
import { build } from "esbuild";
84-
import { lingoCompilerPlugin } from "@lingo.dev/compiler/esbuild";
85-
86-
await build({
87-
plugins: [
88-
lingoCompilerPlugin({
89-
sourceLocale: "en",
90-
targetLocales: ["es", "fr"],
91-
}),
92-
],
93-
});
94-
```
95-
96-
### Next.js
97-
98-
```js
99-
// next.config.js
100-
import { lingoCompilerLoader } from "@lingo.dev/compiler/next";
101-
102-
export default {
103-
webpack: (config) => {
104-
config.module.rules.push({
105-
test: /\.(tsx|jsx)$/,
106-
exclude: /node_modules/,
107-
use: [
108-
{
109-
loader: lingoCompilerLoader,
110-
options: {
111-
sourceLocale: "en",
112-
sourceRoot: "src",
113-
},
114-
},
115-
],
116-
});
117-
return config;
118-
},
119-
};
120-
```
121-
122-
For detailed bundler-specific documentation, see [BUNDLER_SUPPORT.md](./BUNDLER_SUPPORT.md).
123-
12433
## Usage with Turbopack (Next.js 16+)
12534

12635
### 1. Configure Next.js
12736

128-
```javascript
129-
// next.config.js
130-
module.exports = {
131-
turbopack: {
132-
rules: {
133-
"*.{tsx,jsx}": {
134-
loaders: [
135-
{
136-
loader: "@lingo.dev/compiler-beta/loader",
137-
options: {
138-
sourceRoot: "./src", // Root directory of source code
139-
lingoDir: ".lingo", // Directory for metadata
140-
sourceLocale: "en", // Source language
141-
useDirective: false, // Set to true to require 'use i18n' directive
142-
skipPatterns: [/node_modules/, /\.spec\./], // Files to skip
143-
},
144-
},
145-
],
146-
as: "*.js",
147-
},
148-
},
149-
},
150-
};
151-
```
37+
[//]: # ( TODO (AleksandrSl 12/12/2025):
15238

15339
### 2. (Optional) Use directive mode
15440

@@ -194,145 +80,23 @@ export function Welcome() {
19480
}
19581
```
19682

197-
And metadata will be saved to `.lingo/metadata.json`:
198-
199-
```json
200-
{
201-
"version": "0.1",
202-
"entries": {
203-
"a1b2c3d4e5f6": {
204-
"sourceText": "Welcome to our site",
205-
"context": {
206-
"componentName": "Welcome",
207-
"filePath": "src/components/Welcome.tsx",
208-
"line": 4,
209-
"column": 10
210-
},
211-
"hash": "a1b2c3d4e5f6",
212-
"addedAt": "2025-01-17T10:00:00.000Z"
213-
},
214-
"f6e5d4c3b2a1": {
215-
"sourceText": "This text will be automatically translated",
216-
"context": {
217-
"componentName": "Welcome",
218-
"filePath": "src/components/Welcome.tsx",
219-
"line": 5,
220-
"column": 10
221-
},
222-
"hash": "f6e5d4c3b2a1",
223-
"addedAt": "2025-01-17T10:00:00.000Z"
224-
}
225-
},
226-
"stats": {
227-
"totalEntries": 2,
228-
"lastUpdated": "2025-01-17T10:00:00.000Z"
229-
}
230-
}
231-
```
232-
233-
## Programmatic API
234-
235-
You can also use the transformation functions directly:
236-
237-
```typescript
238-
import {
239-
transformComponent,
240-
loadMetadata,
241-
saveMetadata,
242-
generateTranslationHash,
243-
type LoaderConfig,
244-
} from "@lingo.dev/compiler-beta";
245-
246-
// Transform a component
247-
const config: LoaderConfig = {
248-
sourceRoot: "./src",
249-
lingoDir: ".lingo",
250-
sourceLocale: "en",
251-
};
252-
253-
const metadata = await loadMetadata(config);
254-
255-
const result = transformComponent({
256-
code: `export function Hello() { return <div>Hello World</div>; }`,
257-
filePath: "src/Hello.tsx",
258-
config,
259-
metadata,
260-
});
261-
262-
console.log(result.code); // Transformed code
263-
console.log(result.newEntries); // New translation entries found
264-
265-
// Save updated metadata
266-
if (result.newEntries && result.newEntries.length > 0) {
267-
const updatedMetadata = upsertEntries(metadata, result.newEntries);
268-
await saveMetadata(config, updatedMetadata);
269-
}
270-
```
271-
272-
## Architecture
273-
274-
The compiler-beta is designed with a reusable architecture:
275-
276-
- **`src/types.ts`** - TypeScript types and interfaces
277-
- **`src/utils/hash.ts`** - Hash generation utilities
278-
- **`src/metadata/manager.ts`** - Metadata file management
279-
- **`src/transform/babel-plugin.ts`** - Core Babel AST transformation
280-
- **`src/transform/index.ts`** - High-level transformation API
281-
- **`src/loader.ts`** - Turbopack/Webpack loader wrapper
282-
283-
This separation allows the core transformation logic to be reused for other bundlers (e.g., Vite) in the future.
284-
285-
## Configuration Options
286-
287-
| Option | Type | Default | Description |
288-
| -------------- | ---------- | ------------------------------------------ | ----------------------------- |
289-
| `sourceRoot` | `string` | `process.cwd()` | Root directory of source code |
290-
| `lingoDir` | `string` | `'.lingo'` | Directory for Lingo files |
291-
| `sourceLocale` | `string` | `'en'` | Source language code |
292-
| `useDirective` | `boolean` | `false` | Require 'use i18n' directive |
293-
| `skipPatterns` | `RegExp[]` | `[/node_modules/, /\.spec\./, /\.test\./]` | Patterns to skip |
294-
29583
## How It Works
29684

297-
1. **Detection**: Scans JSX files for React components
298-
2. **Extraction**: Finds plain text JSX children (e.g., `<div>Hello</div>`)
299-
3. **Hashing**: Generates unique hash from `sourceText + componentName + filePath`
300-
4. **Transformation**: Replaces text with `{t("hash")}`
301-
5. **Injection**: Adds `const t = useTranslation()` to component
302-
6. **Metadata**: Saves entry to `.lingo/metadata.json`
85+
[//]: # ( TODO (AleksandrSl 12/12/2025):
30386

30487
## Limitations (Current Version)
30588

306-
- Only transforms **plain text** JSX children (no nested elements yet)
307-
- Skips text with only whitespace/newlines
30889
- Requires manual runtime setup (TranslationProvider, etc.)
309-
- Client components only (Server Component support coming)
31090

31191
## Supported Bundlers
31292

31393
| Bundler | Status | Import Path |
31494
| ------- | --------------- | ----------------------------- |
31595
| Vite | ✅ Full Support | `@lingo.dev/compiler/vite` |
31696
| Webpack | ✅ Full Support | `@lingo.dev/compiler/webpack` |
317-
| Rollup | ✅ Full Support | `@lingo.dev/compiler/rollup` |
318-
| esbuild | ✅ Full Support | `@lingo.dev/compiler/esbuild` |
31997
| Next.js | ✅ Full Support | `@lingo.dev/compiler/next` |
32098

321-
All bundler plugins share the same configuration API and are powered by [unplugin](https://github.com/unjs/unplugin).
322-
323-
## Roadmap
324-
325-
- [x] Hash-based metadata system
326-
- [x] Babel transformation plugin
327-
- [x] Turbopack loader
328-
- [x] Multi-bundler support (Vite, Webpack, Rollup, esbuild)
329-
- [x] unplugin-based architecture
330-
- [x] Server Component detection and transformation
331-
- [x] Runtime library integration
332-
- [x] Translation API integration (LCP)
333-
- [ ] JSX attribute translation (alt, title, placeholder)
334-
- [ ] Nested JSX content support
335-
- [ ] React Server Components optimization
99+
All bundler plugins share the same configuration API.
336100

337101
## Contributing
338102

0 commit comments

Comments
 (0)