Skip to content

Commit fe5c378

Browse files
committed
feat: customizable locale change and name without underscore for a package
1 parent 5ff0312 commit fe5c378

47 files changed

Lines changed: 467 additions & 13340 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cmp/compiler/README.md

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ This package provides plugins for multiple bundlers (Vite, Webpack, Rollup, esbu
1818
## Installation
1919

2020
```bash
21-
npm install @lingo.dev/_compiler
21+
npm install @lingo.dev/compiler
2222
# or
23-
pnpm add @lingo.dev/_compiler
23+
pnpm add @lingo.dev/compiler
2424
# or
25-
yarn add @lingo.dev/_compiler
25+
yarn add @lingo.dev/compiler
2626
```
2727

2828
## Quick Start
@@ -32,7 +32,7 @@ yarn add @lingo.dev/_compiler
3232
```ts
3333
// vite.config.ts
3434
import { defineConfig } from "vite";
35-
import { lingoCompilerPlugin } from "@lingo.dev/_compiler/vite";
35+
import { lingoCompilerPlugin } from "@lingo.dev/compiler/vite";
3636

3737
export default defineConfig({
3838
plugins: [
@@ -48,7 +48,7 @@ export default defineConfig({
4848

4949
```js
5050
// webpack.config.js
51-
import { lingoCompilerPlugin } from "@lingo.dev/_compiler/webpack";
51+
import { lingoCompilerPlugin } from "@lingo.dev/compiler/webpack";
5252

5353
export default {
5454
plugins: [
@@ -64,7 +64,7 @@ export default {
6464

6565
```js
6666
// rollup.config.js
67-
import { lingoCompilerPlugin } from "@lingo.dev/_compiler/rollup";
67+
import { lingoCompilerPlugin } from "@lingo.dev/compiler/rollup";
6868

6969
export default {
7070
plugins: [
@@ -81,7 +81,7 @@ export default {
8181
```js
8282
// build.js
8383
import { build } from "esbuild";
84-
import { lingoCompilerPlugin } from "@lingo.dev/_compiler/esbuild";
84+
import { lingoCompilerPlugin } from "@lingo.dev/compiler/esbuild";
8585

8686
await build({
8787
plugins: [
@@ -97,7 +97,7 @@ await build({
9797

9898
```js
9999
// next.config.js
100-
import { lingoCompilerLoader } from "@lingo.dev/_compiler/next";
100+
import { lingoCompilerLoader } from "@lingo.dev/compiler/next";
101101

102102
export default {
103103
webpack: (config) => {
@@ -133,7 +133,7 @@ module.exports = {
133133
"*.{tsx,jsx}": {
134134
loaders: [
135135
{
136-
loader: "@lingo.dev/_compiler-beta/loader",
136+
loader: "@lingo.dev/compiler-beta/loader",
137137
options: {
138138
sourceRoot: "./src", // Root directory of source code
139139
lingoDir: ".lingo", // Directory for metadata
@@ -241,7 +241,7 @@ import {
241241
saveMetadata,
242242
generateTranslationHash,
243243
type LoaderConfig,
244-
} from "@lingo.dev/_compiler-beta";
244+
} from "@lingo.dev/compiler-beta";
245245

246246
// Transform a component
247247
const config: LoaderConfig = {
@@ -310,13 +310,13 @@ This separation allows the core transformation logic to be reused for other bund
310310

311311
## Supported Bundlers
312312

313-
| Bundler | Status | Import Path |
314-
| ------- | --------------- | ------------------------------ |
315-
| Vite | ✅ Full Support | `@lingo.dev/_compiler/vite` |
316-
| Webpack | ✅ Full Support | `@lingo.dev/_compiler/webpack` |
317-
| Rollup | ✅ Full Support | `@lingo.dev/_compiler/rollup` |
318-
| esbuild | ✅ Full Support | `@lingo.dev/_compiler/esbuild` |
319-
| Next.js | ✅ Full Support | `@lingo.dev/_compiler/next` |
313+
| Bundler | Status | Import Path |
314+
| ------- | --------------- | ----------------------------- |
315+
| Vite | ✅ Full Support | `@lingo.dev/compiler/vite` |
316+
| Webpack | ✅ Full Support | `@lingo.dev/compiler/webpack` |
317+
| Rollup | ✅ Full Support | `@lingo.dev/compiler/rollup` |
318+
| esbuild | ✅ Full Support | `@lingo.dev/compiler/esbuild` |
319+
| Next.js | ✅ Full Support | `@lingo.dev/compiler/next` |
320320

321321
All bundler plugins share the same configuration API and are powered by [unplugin](https://github.com/unjs/unplugin).
322322

cmp/compiler/package.json

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "@lingo.dev/_compiler",
2+
"name": "@lingo.dev/compiler",
33
"version": "0.0.1",
44
"description": "Lingo.dev Compiler Beta",
55
"private": false,
@@ -29,16 +29,21 @@
2929
"default": "./build/react/client/index.cjs"
3030
}
3131
},
32-
"./config": {
33-
"types": "./build/config.d.ts",
34-
"import": "./build/config.mjs",
35-
"require": "./build/config.cjs"
36-
},
3732
"./dev-config": {
3833
"types": "./build/dev-config.d.ts",
3934
"import": "./build/dev-config.mjs",
4035
"require": "./build/dev-config.cjs"
4136
},
37+
"./locale/server": {
38+
"types": "./build/locale/server.d.ts",
39+
"import": "./build/locale/server.mjs",
40+
"require": "./build/locale/server.cjs"
41+
},
42+
"./locale/client": {
43+
"types": "./build/locale/client.d.ts",
44+
"import": "./build/locale/client.mjs",
45+
"require": "./build/locale/client.cjs"
46+
},
4247
"./react/client": {
4348
"types": "./build/react/index.d.ts",
4449
"import": "./build/react/index.mjs",
@@ -100,6 +105,16 @@
100105
"types": "./build/plugin/dev-server-loader.d.ts",
101106
"import": "./build/plugin/dev-server-loader.mjs",
102107
"require": "./build/plugin/dev-server-loader.cjs"
108+
},
109+
"./turbopack-locale-server-loader": {
110+
"types": "./build/plugin/turbopack-locale-server-loader.d.ts",
111+
"import": "./build/plugin/turbopack-locale-server-loader.mjs",
112+
"require": "./build/plugin/turbopack-locale-server-loader.cjs"
113+
},
114+
"./turbopack-locale-client-loader": {
115+
"types": "./build/plugin/turbopack-locale-client-loader.d.ts",
116+
"import": "./build/plugin/turbopack-locale-client-loader.mjs",
117+
"require": "./build/plugin/turbopack-locale-client-loader.cjs"
103118
}
104119
},
105120
"files": [

cmp/compiler/src/config.ts

Lines changed: 0 additions & 24 deletions
This file was deleted.

cmp/compiler/src/locale/client.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* Get the current locale on the client
3+
* Reads from cookie
4+
* @returns Resolved locale code
5+
*/
6+
export function getClientLocale(): string {
7+
return "en";
8+
}
9+
10+
const __NOOP_PERSIST_LOCALE__ = () => {};
11+
12+
/**
13+
* Persist the locale on the client
14+
* Writes to cookie
15+
* @param locale - Locale code to persist
16+
*/
17+
export function persistLocale(locale: string): void {
18+
return __NOOP_PERSIST_LOCALE__();
19+
}

cmp/compiler/src/locale/server.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/**
2+
* Get the current locale on the server
3+
* Uses cookies, headers, or other server-side mechanisms
4+
* @returns Resolved locale code
5+
*/
6+
export async function getServerLocale(): Promise<string> {
7+
return "en";
8+
}

cmp/compiler/src/plugin/build-translator.ts

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* - "translate": Generate all translations, fail if translation fails
77
* - "cache-only": Validate cache completeness, fail if incomplete
88
*/
9-
9+
// TODO (AleksandrSl 08/12/2025): Add ICU validation for messages? The problem is that we don't know which will be rendered as a simple text
1010
import fs from "fs/promises";
1111
import path from "path";
1212
import type { LingoConfig, MetadataSchema } from "../types";
@@ -19,17 +19,8 @@ import {
1919
import { loadMetadata } from "../metadata/manager";
2020

2121
export interface BuildTranslationOptions {
22-
/**
23-
* Lingo configuration
24-
*/
2522
config: LingoConfig;
2623

27-
/**
28-
* Build mode (overrides config.buildMode if provided)
29-
* Can be set via LINGO_BUILD_MODE environment variable
30-
*/
31-
buildMode?: "translate" | "cache-only";
32-
3324
/**
3425
* Output directory for static translation files
3526
* If not provided, files won't be generated
@@ -74,12 +65,10 @@ export async function processBuildTranslations(
7465
// Determine build mode (env var > options > config)
7566
const buildMode =
7667
(process.env.LINGO_BUILD_MODE as "translate" | "cache-only") ||
77-
options.buildMode ||
7868
config.buildMode;
7969

8070
logger.info(`🌍 Build mode: ${buildMode}`);
8171

82-
// Load metadata
8372
const metadata = await loadMetadata(config);
8473

8574
if (!metadata || Object.keys(metadata.entries).length === 0) {
@@ -99,7 +88,6 @@ export async function processBuildTranslations(
9988
await validateCache(config, metadata);
10089
logger.info("✅ Cache validation passed");
10190

102-
// Copy cache to public directory if requested
10391
if (publicOutputPath) {
10492
await copyStaticFiles(config, publicOutputPath);
10593
}
@@ -210,7 +198,6 @@ async function validateCache(
210198
const cacheContent = await fs.readFile(cacheFilePath, "utf-8");
211199
const cache = JSON.parse(cacheContent) as Record<string, string>;
212200

213-
// Check if all hashes exist in cache
214201
const missingHashes = allHashes.filter((hash) => !cache[hash]);
215202

216203
if (missingHashes.length > 0) {
@@ -242,9 +229,6 @@ async function validateCache(
242229
}
243230
}
244231

245-
/**
246-
* Build statistics from cache files
247-
*/
248232
function buildCacheStats(
249233
config: LingoConfig,
250234
metadata: MetadataSchema,
@@ -263,9 +247,6 @@ function buildCacheStats(
263247
return stats;
264248
}
265249

266-
/**
267-
* Copy cached translation files to public directory
268-
*/
269250
async function copyStaticFiles(
270251
config: LingoConfig,
271252
publicOutputPath: string,
@@ -288,9 +269,6 @@ async function copyStaticFiles(
288269
}
289270
}
290271

291-
/**
292-
* Format cache validation error message
293-
*/
294272
function formatCacheValidationError(
295273
missingLocales: string[],
296274
incompleteLocales: Array<{ locale: string; missing: number; total: number }>,
@@ -322,9 +300,6 @@ function formatCacheValidationError(
322300
return msg;
323301
}
324302

325-
/**
326-
* Format translation error message
327-
*/
328303
function formatTranslationErrors(
329304
errors: Array<{ locale: string; error: string }>,
330305
): string {

cmp/compiler/src/plugin/dev-server-loader.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export default async function devServerLoader(
1414
if (typeof this.async !== "function") {
1515
throw new Error("This module must be run as a loader");
1616
}
17-
logger.debug("devServerLoader called", this.resourcePath);
17+
logger.debug("Running devServerLoader");
1818
const callback = this.async();
1919
const isDev = process.env.NODE_ENV === "development";
2020

@@ -46,7 +46,6 @@ export default async function devServerLoader(
4646
source
4747
// TODO (AleksandrSl 04/12/2025): Should we just error instead of the default?
4848
.replace("__SERVER_URL__", server?.url || `http://127.0.0.1:${startPort}`)
49-
// TODO (AleksandrSl 04/12/2025): Make cacheDir work
5049
.replace("__CACHE_DIR__", getCacheDir(config)),
5150
);
5251
}

cmp/compiler/src/plugin/esbuild.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* ```js
66
* // build.js
77
* import { build } from 'esbuild';
8-
* import { lingoCompilerPlugin } from '@lingo.dev/_compiler/esbuild';
8+
* import { lingoCompilerPlugin } from '@lingo.dev/compiler/esbuild';
99
*
1010
* await build({
1111
* plugins: [
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* Shared code generation for locale resolution modules
3+
* Used by both unplugin (virtual modules) and Turbopack loaders
4+
*/
5+
6+
import type { LingoConfig } from "../types";
7+
8+
/**
9+
* Generate server-side locale detection code
10+
* Reads locale from cookie
11+
*/
12+
export function generateServerLocaleCode(config: LingoConfig): string {
13+
return `
14+
try {
15+
const { cookies } = await import('next/headers');
16+
const cookieStore = await cookies();
17+
const locale = cookieStore.get(${JSON.stringify(config.cookieConfig.name)})?.value;
18+
return locale || ${JSON.stringify(config.sourceLocale)};
19+
} catch (error) {
20+
// Fallback if cookies are not available
21+
return ${JSON.stringify(config.sourceLocale)};
22+
}`;
23+
}
24+
25+
/**
26+
* Generate client-side locale detection and persistence code
27+
* Includes both getClientLocale() and persistLocale() functions
28+
*/
29+
export function generateClientLocaleCode(config: LingoConfig): {
30+
getClientLocale: string;
31+
persistLocale: string;
32+
} {
33+
const cookieName = config.cookieConfig.name;
34+
const maxAge = config.cookieConfig.maxAge;
35+
36+
return {
37+
getClientLocale: `
38+
if (typeof document !== 'undefined') {
39+
const match = document.cookie.match(/${cookieName}=([^;]+)/);
40+
if (match) return match[1];
41+
}
42+
// Fallback to source locale
43+
return ${JSON.stringify(config.sourceLocale)};
44+
`,
45+
persistLocale: `if (typeof document !== 'undefined') {
46+
document.cookie = \`${cookieName}=\${locale}; path=/; max-age=${maxAge}\`;
47+
}`,
48+
};
49+
}

0 commit comments

Comments
 (0)