@lingo.dev/compiler 0.3.10 → 0.3.12

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.
@@ -5,7 +5,6 @@ let path = require("path");
5
5
  path = require_rolldown_runtime.__toESM(path);
6
6
  let fs = require("fs");
7
7
  fs = require_rolldown_runtime.__toESM(fs);
8
- let lmdb = require("lmdb");
9
8
 
10
9
  //#region src/metadata/manager.ts
11
10
  const METADATA_DIR_DEV = "metadata-dev";
@@ -15,11 +14,15 @@ const METADATA_DIR_BUILD = "metadata-build";
15
14
  *
16
15
  * lmdb-js deduplicates open() calls to the same path (ref-counted at C++ level),
17
16
  * so this is cheap. Each open() also clears stale readers from terminated workers.
17
+ *
18
+ * lmdb is loaded via dynamic import() to prevent bundlers and require hooks
19
+ * from transforming its CJS bundle, which contains syntax they can't handle.
18
20
  */
19
- function openDatabaseConnection(dbPath, noSync) {
21
+ async function openDatabaseConnection(dbPath, noSync) {
20
22
  try {
21
23
  fs.default.mkdirSync(dbPath, { recursive: true });
22
- return (0, lmdb.open)({
24
+ const { open } = await import("lmdb");
25
+ return open({
23
26
  path: dbPath,
24
27
  compression: true,
25
28
  noSync
@@ -45,7 +48,7 @@ async function closeDatabaseConnection(db, dbPath) {
45
48
  * is closed afterwards.
46
49
  */
47
50
  async function runWithDbConnection(dbPath, noSync, fn) {
48
- const db = openDatabaseConnection(dbPath, noSync);
51
+ const db = await openDatabaseConnection(dbPath, noSync);
49
52
  try {
50
53
  return fn(db);
51
54
  } finally {
@@ -2,7 +2,6 @@ import { logger } from "../utils/logger.mjs";
2
2
  import { getLingoDir } from "../utils/path-helpers.mjs";
3
3
  import path from "path";
4
4
  import fs from "fs";
5
- import { open } from "lmdb";
6
5
 
7
6
  //#region src/metadata/manager.ts
8
7
  const METADATA_DIR_DEV = "metadata-dev";
@@ -12,10 +11,14 @@ const METADATA_DIR_BUILD = "metadata-build";
12
11
  *
13
12
  * lmdb-js deduplicates open() calls to the same path (ref-counted at C++ level),
14
13
  * so this is cheap. Each open() also clears stale readers from terminated workers.
14
+ *
15
+ * lmdb is loaded via dynamic import() to prevent bundlers and require hooks
16
+ * from transforming its CJS bundle, which contains syntax they can't handle.
15
17
  */
16
- function openDatabaseConnection(dbPath, noSync) {
18
+ async function openDatabaseConnection(dbPath, noSync) {
17
19
  try {
18
20
  fs.mkdirSync(dbPath, { recursive: true });
21
+ const { open } = await import("lmdb");
19
22
  return open({
20
23
  path: dbPath,
21
24
  compression: true,
@@ -42,7 +45,7 @@ async function closeDatabaseConnection(db, dbPath) {
42
45
  * is closed afterwards.
43
46
  */
44
47
  async function runWithDbConnection(dbPath, noSync, fn) {
45
- const db = openDatabaseConnection(dbPath, noSync);
48
+ const db = await openDatabaseConnection(dbPath, noSync);
46
49
  try {
47
50
  return fn(db);
48
51
  } finally {
@@ -1 +1 @@
1
- {"version":3,"file":"manager.mjs","names":["entries: MetadataSchema"],"sources":["../../src/metadata/manager.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport { open, type RootDatabase } from \"lmdb\";\nimport type { MetadataSchema, PathConfig, TranslationEntry } from \"../types\";\nimport { getLingoDir } from \"../utils/path-helpers\";\nimport { logger } from \"../utils/logger\";\n\nconst METADATA_DIR_DEV = \"metadata-dev\";\nconst METADATA_DIR_BUILD = \"metadata-build\";\n\n/**\n * Opens an LMDB connection for a single operation.\n *\n * lmdb-js deduplicates open() calls to the same path (ref-counted at C++ level),\n * so this is cheap. Each open() also clears stale readers from terminated workers.\n */\nfunction openDatabaseConnection(dbPath: string, noSync: boolean): RootDatabase {\n try {\n fs.mkdirSync(dbPath, { recursive: true });\n return open({\n path: dbPath,\n compression: true,\n noSync,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to open LMDB at ${dbPath}: ${message}`);\n }\n}\n\n/**\n * Closes the LMDB connection. Also prevents EBUSY/EPERM on Windows during\n * directory cleanup.\n */\nasync function closeDatabaseConnection(\n db: RootDatabase,\n dbPath: string,\n): Promise<void> {\n try {\n await db.close();\n } catch (e) {\n logger.debug(`Error closing database at ${dbPath}: ${e}`);\n }\n}\n\n/**\n * Opens a database connection, runs the callback, and ensures the connection\n * is closed afterwards.\n */\nasync function runWithDbConnection<T>(\n dbPath: string,\n noSync: boolean,\n fn: (db: RootDatabase) => T,\n): Promise<T> {\n const db = openDatabaseConnection(dbPath, noSync);\n try {\n return fn(db);\n } finally {\n await closeDatabaseConnection(db, dbPath);\n }\n}\n\nfunction readEntriesFromDb(db: RootDatabase): MetadataSchema {\n const entries: MetadataSchema = {};\n\n for (const { key, value } of db.getRange()) {\n entries[key as string] = value as TranslationEntry;\n }\n\n return entries;\n}\n\nexport async function loadMetadata(\n dbPath: string,\n noSync = false,\n): Promise<MetadataSchema> {\n return runWithDbConnection(dbPath, noSync, readEntriesFromDb);\n}\n\n/**\n * Persists translation entries to LMDB in a single atomic transaction.\n */\nexport async function saveMetadata(\n dbPath: string,\n entries: TranslationEntry[],\n noSync = false,\n): Promise<void> {\n return runWithDbConnection(dbPath, noSync, (db) => {\n db.transactionSync(() => {\n for (const entry of entries) {\n db.putSync(entry.hash, entry);\n }\n });\n });\n}\n\nexport function cleanupExistingMetadata(metadataDbPath: string): void {\n logger.debug(`Cleaning up metadata database: ${metadataDbPath}`);\n\n try {\n fs.rmSync(metadataDbPath, { recursive: true, force: true });\n logger.info(`🧹 Cleaned up metadata database: ${metadataDbPath}`);\n } catch (error) {\n const code =\n error instanceof Error && \"code\" in error\n ? (error as NodeJS.ErrnoException).code\n : undefined;\n const message = error instanceof Error ? error.message : String(error);\n\n if (code === \"ENOENT\") {\n logger.debug(\n `Metadata database already deleted or doesn't exist: ${metadataDbPath}`,\n );\n return;\n }\n\n logger.warn(`Failed to cleanup metadata database: ${message}`);\n }\n}\n\nexport function getMetadataPath(config: PathConfig): string {\n const dirname =\n config.environment === \"development\"\n ? METADATA_DIR_DEV\n : METADATA_DIR_BUILD;\n return path.join(getLingoDir(config), dirname);\n}\n"],"mappings":";;;;;;;AAOA,MAAM,mBAAmB;AACzB,MAAM,qBAAqB;;;;;;;AAQ3B,SAAS,uBAAuB,QAAgB,QAA+B;AAC7E,KAAI;AACF,KAAG,UAAU,QAAQ,EAAE,WAAW,MAAM,CAAC;AACzC,SAAO,KAAK;GACV,MAAM;GACN,aAAa;GACb;GACD,CAAC;UACK,OAAO;EACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,QAAM,IAAI,MAAM,0BAA0B,OAAO,IAAI,UAAU;;;;;;;AAQnE,eAAe,wBACb,IACA,QACe;AACf,KAAI;AACF,QAAM,GAAG,OAAO;UACT,GAAG;AACV,SAAO,MAAM,6BAA6B,OAAO,IAAI,IAAI;;;;;;;AAQ7D,eAAe,oBACb,QACA,QACA,IACY;CACZ,MAAM,KAAK,uBAAuB,QAAQ,OAAO;AACjD,KAAI;AACF,SAAO,GAAG,GAAG;WACL;AACR,QAAM,wBAAwB,IAAI,OAAO;;;AAI7C,SAAS,kBAAkB,IAAkC;CAC3D,MAAMA,UAA0B,EAAE;AAElC,MAAK,MAAM,EAAE,KAAK,WAAW,GAAG,UAAU,CACxC,SAAQ,OAAiB;AAG3B,QAAO;;AAGT,eAAsB,aACpB,QACA,SAAS,OACgB;AACzB,QAAO,oBAAoB,QAAQ,QAAQ,kBAAkB;;;;;AAM/D,eAAsB,aACpB,QACA,SACA,SAAS,OACM;AACf,QAAO,oBAAoB,QAAQ,SAAS,OAAO;AACjD,KAAG,sBAAsB;AACvB,QAAK,MAAM,SAAS,QAClB,IAAG,QAAQ,MAAM,MAAM,MAAM;IAE/B;GACF;;AAGJ,SAAgB,wBAAwB,gBAA8B;AACpE,QAAO,MAAM,kCAAkC,iBAAiB;AAEhE,KAAI;AACF,KAAG,OAAO,gBAAgB;GAAE,WAAW;GAAM,OAAO;GAAM,CAAC;AAC3D,SAAO,KAAK,oCAAoC,iBAAiB;UAC1D,OAAO;EACd,MAAM,OACJ,iBAAiB,SAAS,UAAU,QAC/B,MAAgC,OACjC;EACN,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AAEtE,MAAI,SAAS,UAAU;AACrB,UAAO,MACL,uDAAuD,iBACxD;AACD;;AAGF,SAAO,KAAK,wCAAwC,UAAU;;;AAIlE,SAAgB,gBAAgB,QAA4B;CAC1D,MAAM,UACJ,OAAO,gBAAgB,gBACnB,mBACA;AACN,QAAO,KAAK,KAAK,YAAY,OAAO,EAAE,QAAQ"}
1
+ {"version":3,"file":"manager.mjs","names":["entries: MetadataSchema"],"sources":["../../src/metadata/manager.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport type { RootDatabase } from \"lmdb\";\nimport type { MetadataSchema, PathConfig, TranslationEntry } from \"../types\";\nimport { getLingoDir } from \"../utils/path-helpers\";\nimport { logger } from \"../utils/logger\";\n\nconst METADATA_DIR_DEV = \"metadata-dev\";\nconst METADATA_DIR_BUILD = \"metadata-build\";\n\n/**\n * Opens an LMDB connection for a single operation.\n *\n * lmdb-js deduplicates open() calls to the same path (ref-counted at C++ level),\n * so this is cheap. Each open() also clears stale readers from terminated workers.\n *\n * lmdb is loaded via dynamic import() to prevent bundlers and require hooks\n * from transforming its CJS bundle, which contains syntax they can't handle.\n */\nasync function openDatabaseConnection(dbPath: string, noSync: boolean): Promise<RootDatabase> {\n try {\n fs.mkdirSync(dbPath, { recursive: true });\n const { open } = await import(\"lmdb\");\n return open({\n path: dbPath,\n compression: true,\n noSync,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to open LMDB at ${dbPath}: ${message}`);\n }\n}\n\n/**\n * Closes the LMDB connection. Also prevents EBUSY/EPERM on Windows during\n * directory cleanup.\n */\nasync function closeDatabaseConnection(\n db: RootDatabase,\n dbPath: string,\n): Promise<void> {\n try {\n await db.close();\n } catch (e) {\n logger.debug(`Error closing database at ${dbPath}: ${e}`);\n }\n}\n\n/**\n * Opens a database connection, runs the callback, and ensures the connection\n * is closed afterwards.\n */\nasync function runWithDbConnection<T>(\n dbPath: string,\n noSync: boolean,\n fn: (db: RootDatabase) => T,\n): Promise<T> {\n const db = await openDatabaseConnection(dbPath, noSync);\n try {\n return fn(db);\n } finally {\n await closeDatabaseConnection(db, dbPath);\n }\n}\n\nfunction readEntriesFromDb(db: RootDatabase): MetadataSchema {\n const entries: MetadataSchema = {};\n\n for (const { key, value } of db.getRange()) {\n entries[key as string] = value as TranslationEntry;\n }\n\n return entries;\n}\n\nexport async function loadMetadata(\n dbPath: string,\n noSync = false,\n): Promise<MetadataSchema> {\n return runWithDbConnection(dbPath, noSync, readEntriesFromDb);\n}\n\n/**\n * Persists translation entries to LMDB in a single atomic transaction.\n */\nexport async function saveMetadata(\n dbPath: string,\n entries: TranslationEntry[],\n noSync = false,\n): Promise<void> {\n return runWithDbConnection(dbPath, noSync, (db) => {\n db.transactionSync(() => {\n for (const entry of entries) {\n db.putSync(entry.hash, entry);\n }\n });\n });\n}\n\nexport function cleanupExistingMetadata(metadataDbPath: string): void {\n logger.debug(`Cleaning up metadata database: ${metadataDbPath}`);\n\n try {\n fs.rmSync(metadataDbPath, { recursive: true, force: true });\n logger.info(`🧹 Cleaned up metadata database: ${metadataDbPath}`);\n } catch (error) {\n const code =\n error instanceof Error && \"code\" in error\n ? (error as NodeJS.ErrnoException).code\n : undefined;\n const message = error instanceof Error ? error.message : String(error);\n\n if (code === \"ENOENT\") {\n logger.debug(\n `Metadata database already deleted or doesn't exist: ${metadataDbPath}`,\n );\n return;\n }\n\n logger.warn(`Failed to cleanup metadata database: ${message}`);\n }\n}\n\nexport function getMetadataPath(config: PathConfig): string {\n const dirname =\n config.environment === \"development\"\n ? METADATA_DIR_DEV\n : METADATA_DIR_BUILD;\n return path.join(getLingoDir(config), dirname);\n}\n"],"mappings":";;;;;;AAOA,MAAM,mBAAmB;AACzB,MAAM,qBAAqB;;;;;;;;;;AAW3B,eAAe,uBAAuB,QAAgB,QAAwC;AAC5F,KAAI;AACF,KAAG,UAAU,QAAQ,EAAE,WAAW,MAAM,CAAC;EACzC,MAAM,EAAE,SAAS,MAAM,OAAO;AAC9B,SAAO,KAAK;GACV,MAAM;GACN,aAAa;GACb;GACD,CAAC;UACK,OAAO;EACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,QAAM,IAAI,MAAM,0BAA0B,OAAO,IAAI,UAAU;;;;;;;AAQnE,eAAe,wBACb,IACA,QACe;AACf,KAAI;AACF,QAAM,GAAG,OAAO;UACT,GAAG;AACV,SAAO,MAAM,6BAA6B,OAAO,IAAI,IAAI;;;;;;;AAQ7D,eAAe,oBACb,QACA,QACA,IACY;CACZ,MAAM,KAAK,MAAM,uBAAuB,QAAQ,OAAO;AACvD,KAAI;AACF,SAAO,GAAG,GAAG;WACL;AACR,QAAM,wBAAwB,IAAI,OAAO;;;AAI7C,SAAS,kBAAkB,IAAkC;CAC3D,MAAMA,UAA0B,EAAE;AAElC,MAAK,MAAM,EAAE,KAAK,WAAW,GAAG,UAAU,CACxC,SAAQ,OAAiB;AAG3B,QAAO;;AAGT,eAAsB,aACpB,QACA,SAAS,OACgB;AACzB,QAAO,oBAAoB,QAAQ,QAAQ,kBAAkB;;;;;AAM/D,eAAsB,aACpB,QACA,SACA,SAAS,OACM;AACf,QAAO,oBAAoB,QAAQ,SAAS,OAAO;AACjD,KAAG,sBAAsB;AACvB,QAAK,MAAM,SAAS,QAClB,IAAG,QAAQ,MAAM,MAAM,MAAM;IAE/B;GACF;;AAGJ,SAAgB,wBAAwB,gBAA8B;AACpE,QAAO,MAAM,kCAAkC,iBAAiB;AAEhE,KAAI;AACF,KAAG,OAAO,gBAAgB;GAAE,WAAW;GAAM,OAAO;GAAM,CAAC;AAC3D,SAAO,KAAK,oCAAoC,iBAAiB;UAC1D,OAAO;EACd,MAAM,OACJ,iBAAiB,SAAS,UAAU,QAC/B,MAAgC,OACjC;EACN,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AAEtE,MAAI,SAAS,UAAU;AACrB,UAAO,MACL,uDAAuD,iBACxD;AACD;;AAGF,SAAO,KAAK,wCAAwC,UAAU;;;AAIlE,SAAgB,gBAAgB,QAA4B;CAC1D,MAAM,UACJ,OAAO,gBAAgB,gBACnB,mBACA;AACN,QAAO,KAAK,KAAK,YAAY,OAAO,EAAE,QAAQ"}
@@ -133,7 +133,10 @@ async function withLingo(nextConfig = {}, lingoOptions) {
133
133
  let metadataFilePath = require_manager.getMetadataPath(lingoConfig);
134
134
  const isDev = lingoConfig.environment === "development";
135
135
  require_logger.logger.debug(`Initializing Lingo.dev compiler. Is dev mode: ${isDev}. Is main runner: ${isMainRunner()}`);
136
- if (isDev && !process.env.LINGO_TRANSLATION_SERVER_URL) {
136
+ if (isDev && !process.env.LINGO_TRANSLATION_SERVER_URL) if (lingoConfig.dev.translationServerUrl) {
137
+ require_logger.logger.info(`Using existing translation server URL (${lingoConfig.dev.translationServerUrl}) from config`);
138
+ process.env.LINGO_TRANSLATION_SERVER_URL = lingoConfig.dev.translationServerUrl;
139
+ } else {
137
140
  const translationServer = await require_translation_server.startOrGetTranslationServer({
138
141
  translationService: new require_translation_service.TranslationService(lingoConfig, require_logger.logger),
139
142
  onError: (err) => {
@@ -134,7 +134,10 @@ async function withLingo(nextConfig = {}, lingoOptions) {
134
134
  let metadataFilePath = getMetadataPath(lingoConfig);
135
135
  const isDev = lingoConfig.environment === "development";
136
136
  logger.debug(`Initializing Lingo.dev compiler. Is dev mode: ${isDev}. Is main runner: ${isMainRunner()}`);
137
- if (isDev && !process.env.LINGO_TRANSLATION_SERVER_URL) {
137
+ if (isDev && !process.env.LINGO_TRANSLATION_SERVER_URL) if (lingoConfig.dev.translationServerUrl) {
138
+ logger.info(`Using existing translation server URL (${lingoConfig.dev.translationServerUrl}) from config`);
139
+ process.env.LINGO_TRANSLATION_SERVER_URL = lingoConfig.dev.translationServerUrl;
140
+ } else {
138
141
  const translationServer = await startOrGetTranslationServer({
139
142
  translationService: new TranslationService(lingoConfig, logger),
140
143
  onError: (err) => {
@@ -1 +1 @@
1
- {"version":3,"file":"next.mjs","names":["turbopackConfig: Partial<NextConfig>","webpack: NextJsWebpackConfig"],"sources":["../../src/plugin/next.ts"],"sourcesContent":["import type { NextConfig } from \"next\";\nimport type {\n NextJsWebpackConfig,\n TurbopackOptions,\n WebpackConfigContext,\n} from \"next/dist/server/config-shared\";\nimport { createLingoConfig } from \"../utils/config-factory\";\nimport { logger } from \"../utils/logger\";\nimport type { LingoConfig, PartialLingoConfig } from \"../types\";\nimport { processBuildTranslations } from \"./build-translator\";\nimport { startOrGetTranslationServer } from \"../translation-server/translation-server\";\nimport { cleanupExistingMetadata, getMetadataPath } from \"../metadata/manager\";\nimport { registerCleanupOnCurrentProcess } from \"./cleanup\";\nimport { useI18nRegex } from \"./transform/use-i18n\";\nimport { TranslationService } from \"../translators\";\n\nexport type LingoNextPluginOptions = PartialLingoConfig;\n\ntype RuleKey = \"compiler\" | \"devConfig\" | \"localeServer\" | \"localeClient\";\n\nfunction loaders({\n lingoConfig,\n metadataFilePath,\n translationServerUrl,\n}: {\n lingoConfig: LingoConfig;\n metadataFilePath: string;\n translationServerUrl?: string;\n}): Record<RuleKey, { turbopack?: any; webpack?: any }> {\n const common = {\n sourceRoot: lingoConfig.sourceRoot,\n lingoDir: lingoConfig.lingoDir,\n sourceLocale: lingoConfig.sourceLocale,\n };\n\n // TODO (AleksandrSl 14/12/2025): Type options.\n const compilerLoader = {\n loader: \"@lingo.dev/compiler/next-compiler-loader\",\n options: {\n ...common,\n useDirective: lingoConfig.useDirective,\n metadataFilePath,\n },\n };\n\n const configLoader = {\n loader: \"@lingo.dev/compiler/next-config-loader\",\n options: {\n ...common,\n dev: {\n translationServerUrl,\n ...lingoConfig.dev,\n },\n },\n };\n const localeServerLoader = {\n loader: \"@lingo.dev/compiler/next-locale-server-loader\",\n options: {\n ...common,\n localePersistence: lingoConfig.localePersistence,\n },\n };\n\n const localeClientLoader = {\n loader: \"@lingo.dev/compiler/next-locale-client-loader\",\n options: {\n ...common,\n localePersistence: lingoConfig.localePersistence,\n },\n };\n\n return {\n compiler: {\n turbopack: {\n pattern: \"*.{tsx,jsx}\",\n config: {\n condition: {\n content: lingoConfig.useDirective ? useI18nRegex : undefined,\n },\n loaders: [compilerLoader],\n },\n },\n webpack: {\n enforce: \"pre\",\n test: /\\.(tsx|jsx)$/i,\n exclude: /node_modules/,\n use: [compilerLoader],\n },\n },\n\n devConfig: translationServerUrl\n ? {\n turbopack: {\n pattern: \"**/virtual/config.mjs\",\n config: {\n loaders: [configLoader],\n },\n },\n webpack: {\n enforce: \"pre\",\n test: /virtual\\/config\\.mjs$/i,\n use: [configLoader],\n },\n }\n : {},\n\n localeServer: {\n turbopack: {\n pattern: \"**/virtual/locale/server.mjs\",\n config: {\n loaders: [localeServerLoader],\n },\n },\n webpack: {\n enforce: \"pre\",\n test: /virtual\\/locale[\\\\/]server\\.mjs$/i,\n use: [localeServerLoader],\n },\n },\n\n localeClient: {\n turbopack: {\n pattern: \"**/virtual/locale/client.mjs\",\n config: {\n loaders: [localeClientLoader],\n },\n },\n webpack: {\n enforce: \"pre\",\n test: /virtual\\/locale[\\\\/]client\\.mjs$/i,\n use: [localeClientLoader],\n },\n },\n };\n}\n\n/**\n * Check if Next.js supports stable turbopack config (Next.js 16+)\n */\nfunction hasStableTurboConfig(): boolean {\n try {\n const nextPackage = require(\"next/package.json\");\n const majorVersion = parseInt(nextPackage.version.split(\".\")[0], 10);\n return majorVersion >= 16;\n } catch {\n return false;\n }\n}\n\nfunction getTurbopackConfig(userConfig: NextConfig): TurbopackOptions {\n return (\n (hasStableTurboConfig()\n ? userConfig?.turbopack?.rules\n : // @ts-expect-error - experimental.turbo for Next.js <16\n userConfig?.experimental?.turbo) || {}\n );\n}\n\n/**\n * Merge Turbopack rules without mutating original\n */\nfunction mergeTurbopackRules(\n existingRules: Record<string, any>,\n newRules: ({ pattern: string; config: any } | undefined)[],\n): Record<string, any> {\n const mergedRules = { ...existingRules };\n\n for (const newRule of newRules) {\n if (!newRule) continue;\n const { pattern, config } = newRule;\n\n if (mergedRules[pattern]) {\n if (Array.isArray(mergedRules[pattern])) {\n mergedRules[pattern] = [...mergedRules[pattern], config];\n } else {\n mergedRules[pattern] = [mergedRules[pattern], config];\n }\n } else {\n mergedRules[pattern] = config;\n }\n }\n\n return mergedRules;\n}\n\n// Next read config several times. Once in the main runner,\n// and ~ twice in the build workers which cannot get the config otherwise, because it's not serializable.\n// Workers start in separate processed by get most of the env from the main loader\nfunction isMainRunner() {\n return (\n !process.env.NEXT_PRIVATE_BUILD_WORKER &&\n !process.env.IS_NEXT_WORKER &&\n !process.env.NEXT_PRIVATE_WORKER\n );\n}\n\nexport async function withLingo(\n nextConfig: NextConfig = {},\n lingoOptions: LingoNextPluginOptions,\n): Promise<NextConfig> {\n const lingoConfig = createLingoConfig(lingoOptions);\n let metadataFilePath = getMetadataPath(lingoConfig);\n const isDev = lingoConfig.environment === \"development\";\n\n logger.debug(\n `Initializing Lingo.dev compiler. Is dev mode: ${isDev}. Is main runner: ${isMainRunner()}`,\n );\n\n // Try to start up the translation server once.\n // We have two barriers, a simple one here and a more complex one inside the startTranslationServer which doesn't start the server if it can find one running.\n // We do not use isMainRunner here, because we need to start the server as early as possible, so the loaders get the translation server url. The main runner in dev mode runs after a dev server process is started.\n if (isDev && !process.env.LINGO_TRANSLATION_SERVER_URL) {\n const translationServer = await startOrGetTranslationServer({\n translationService: new TranslationService(lingoConfig, logger),\n onError: (err) => {\n logger.error(\"Translation server error:\", err);\n },\n onReady: (port) => {\n logger.info(`Translation server started successfully on port: ${port}`);\n },\n config: lingoConfig,\n });\n process.env.LINGO_TRANSLATION_SERVER_URL = translationServer.url;\n if (translationServer.server) {\n // We start the server in the same process, so we should be fine without any sync cleanup. Server should be killed with the process.\n registerCleanupOnCurrentProcess({\n asyncCleanup: async () => {\n await translationServer.server.stop();\n },\n });\n }\n }\n\n const translationServerUrl = process.env.LINGO_TRANSLATION_SERVER_URL;\n\n if (isMainRunner()) {\n // We need to cleaup the file only once, to avoid having extra translation introduced into the build, or old translation to pile up.\n cleanupExistingMetadata(metadataFilePath);\n\n registerCleanupOnCurrentProcess({\n cleanup: () => cleanupExistingMetadata(metadataFilePath),\n });\n }\n\n const existingTurbopackConfig = getTurbopackConfig(nextConfig);\n let mergedRules = mergeTurbopackRules(\n existingTurbopackConfig.rules ?? {},\n Object.values(\n loaders({ lingoConfig, metadataFilePath, translationServerUrl }),\n ).map((rules) => rules.turbopack),\n );\n\n const existingResolveAlias = existingTurbopackConfig.resolveAlias;\n const mergedResolveAlias = {\n ...existingResolveAlias,\n // TODO (AleksandrSl 08/12/2025): Describe what have to be done to support custom resolvers\n };\n\n let turbopackConfig: Partial<NextConfig>;\n if (hasStableTurboConfig()) {\n turbopackConfig = {\n turbopack: {\n ...nextConfig.turbopack, // Preserve existing turbopack options\n rules: mergedRules,\n resolveAlias: mergedResolveAlias,\n },\n };\n } else {\n turbopackConfig = {\n experimental: {\n ...nextConfig.experimental, // Preserve ALL experimental options\n // @ts-expect-error - turbo for Next.js <16\n turbo: {\n // @ts-expect-error - turbo for Next.js <16\n ...nextConfig.experimental?.turbo, // Preserve existing turbo options\n rules: mergedRules,\n resolveAlias: mergedResolveAlias,\n },\n },\n };\n }\n\n const runAfterProductionCompile = async ({\n distDir,\n projectDir,\n }: {\n distDir: string;\n projectDir: string;\n }) => {\n if (typeof nextConfig.compiler?.runAfterProductionCompile === \"function\") {\n await nextConfig.compiler.runAfterProductionCompile({\n distDir,\n projectDir,\n });\n }\n\n logger.info(\"Running post-build translation generation...\");\n\n try {\n await processBuildTranslations({\n config: lingoConfig,\n publicOutputPath: distDir,\n metadataFilePath,\n });\n } catch (error) {\n logger.error(\n \"Translation generation failed:\",\n error instanceof Error ? error.message : error,\n );\n throw error;\n }\n };\n\n const webpack: NextJsWebpackConfig = (\n config: any,\n options: WebpackConfigContext,\n ) => {\n // Apply user's webpack config first if it exists\n let modifiedConfig = config;\n if (typeof nextConfig.webpack === \"function\") {\n modifiedConfig = nextConfig.webpack(config, options);\n }\n\n const lingoRules = Object.values(\n loaders({ lingoConfig, metadataFilePath, translationServerUrl }),\n )\n .map((rules) => rules.webpack)\n .filter(Boolean);\n\n // I tried using plugin from unplugin, but with all the loaders stuff it works poorly.\n // Failing with weird errors which appear on the later compilations, probably something with the cache and virtual modules\n modifiedConfig.module.rules.unshift(...lingoRules);\n\n return modifiedConfig;\n };\n\n return {\n ...nextConfig,\n ...turbopackConfig,\n compiler: {\n ...nextConfig.compiler,\n runAfterProductionCompile,\n },\n webpack,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"next.mjs","names":["turbopackConfig: Partial<NextConfig>","webpack: NextJsWebpackConfig"],"sources":["../../src/plugin/next.ts"],"sourcesContent":["import type { NextConfig } from \"next\";\nimport type {\n NextJsWebpackConfig,\n TurbopackOptions,\n WebpackConfigContext,\n} from \"next/dist/server/config-shared\";\nimport { createLingoConfig } from \"../utils/config-factory\";\nimport { logger } from \"../utils/logger\";\nimport type { LingoConfig, PartialLingoConfig } from \"../types\";\nimport { processBuildTranslations } from \"./build-translator\";\nimport { startOrGetTranslationServer } from \"../translation-server/translation-server\";\nimport { cleanupExistingMetadata, getMetadataPath } from \"../metadata/manager\";\nimport { registerCleanupOnCurrentProcess } from \"./cleanup\";\nimport { useI18nRegex } from \"./transform/use-i18n\";\nimport { TranslationService } from \"../translators\";\n\nexport type LingoNextPluginOptions = PartialLingoConfig;\n\ntype RuleKey = \"compiler\" | \"devConfig\" | \"localeServer\" | \"localeClient\";\n\nfunction loaders({\n lingoConfig,\n metadataFilePath,\n translationServerUrl,\n}: {\n lingoConfig: LingoConfig;\n metadataFilePath: string;\n translationServerUrl?: string;\n}): Record<RuleKey, { turbopack?: any; webpack?: any }> {\n const common = {\n sourceRoot: lingoConfig.sourceRoot,\n lingoDir: lingoConfig.lingoDir,\n sourceLocale: lingoConfig.sourceLocale,\n };\n\n // TODO (AleksandrSl 14/12/2025): Type options.\n const compilerLoader = {\n loader: \"@lingo.dev/compiler/next-compiler-loader\",\n options: {\n ...common,\n useDirective: lingoConfig.useDirective,\n metadataFilePath,\n },\n };\n\n const configLoader = {\n loader: \"@lingo.dev/compiler/next-config-loader\",\n options: {\n ...common,\n dev: {\n translationServerUrl,\n ...lingoConfig.dev,\n },\n },\n };\n const localeServerLoader = {\n loader: \"@lingo.dev/compiler/next-locale-server-loader\",\n options: {\n ...common,\n localePersistence: lingoConfig.localePersistence,\n },\n };\n\n const localeClientLoader = {\n loader: \"@lingo.dev/compiler/next-locale-client-loader\",\n options: {\n ...common,\n localePersistence: lingoConfig.localePersistence,\n },\n };\n\n return {\n compiler: {\n turbopack: {\n pattern: \"*.{tsx,jsx}\",\n config: {\n condition: {\n content: lingoConfig.useDirective ? useI18nRegex : undefined,\n },\n loaders: [compilerLoader],\n },\n },\n webpack: {\n enforce: \"pre\",\n test: /\\.(tsx|jsx)$/i,\n exclude: /node_modules/,\n use: [compilerLoader],\n },\n },\n\n devConfig: translationServerUrl\n ? {\n turbopack: {\n pattern: \"**/virtual/config.mjs\",\n config: {\n loaders: [configLoader],\n },\n },\n webpack: {\n enforce: \"pre\",\n test: /virtual\\/config\\.mjs$/i,\n use: [configLoader],\n },\n }\n : {},\n\n localeServer: {\n turbopack: {\n pattern: \"**/virtual/locale/server.mjs\",\n config: {\n loaders: [localeServerLoader],\n },\n },\n webpack: {\n enforce: \"pre\",\n test: /virtual\\/locale[\\\\/]server\\.mjs$/i,\n use: [localeServerLoader],\n },\n },\n\n localeClient: {\n turbopack: {\n pattern: \"**/virtual/locale/client.mjs\",\n config: {\n loaders: [localeClientLoader],\n },\n },\n webpack: {\n enforce: \"pre\",\n test: /virtual\\/locale[\\\\/]client\\.mjs$/i,\n use: [localeClientLoader],\n },\n },\n };\n}\n\n/**\n * Check if Next.js supports stable turbopack config (Next.js 16+)\n */\nfunction hasStableTurboConfig(): boolean {\n try {\n const nextPackage = require(\"next/package.json\");\n const majorVersion = parseInt(nextPackage.version.split(\".\")[0], 10);\n return majorVersion >= 16;\n } catch {\n return false;\n }\n}\n\nfunction getTurbopackConfig(userConfig: NextConfig): TurbopackOptions {\n return (\n (hasStableTurboConfig()\n ? userConfig?.turbopack?.rules\n : // @ts-expect-error - experimental.turbo for Next.js <16\n userConfig?.experimental?.turbo) || {}\n );\n}\n\n/**\n * Merge Turbopack rules without mutating original\n */\nfunction mergeTurbopackRules(\n existingRules: Record<string, any>,\n newRules: ({ pattern: string; config: any } | undefined)[],\n): Record<string, any> {\n const mergedRules = { ...existingRules };\n\n for (const newRule of newRules) {\n if (!newRule) continue;\n const { pattern, config } = newRule;\n\n if (mergedRules[pattern]) {\n if (Array.isArray(mergedRules[pattern])) {\n mergedRules[pattern] = [...mergedRules[pattern], config];\n } else {\n mergedRules[pattern] = [mergedRules[pattern], config];\n }\n } else {\n mergedRules[pattern] = config;\n }\n }\n\n return mergedRules;\n}\n\n// Next read config several times. Once in the main runner,\n// and ~ twice in the build workers which cannot get the config otherwise, because it's not serializable.\n// Workers start in separate processed by get most of the env from the main loader\nfunction isMainRunner() {\n return (\n !process.env.NEXT_PRIVATE_BUILD_WORKER &&\n !process.env.IS_NEXT_WORKER &&\n !process.env.NEXT_PRIVATE_WORKER\n );\n}\n\nexport async function withLingo(\n nextConfig: NextConfig = {},\n lingoOptions: LingoNextPluginOptions,\n): Promise<NextConfig> {\n const lingoConfig = createLingoConfig(lingoOptions);\n let metadataFilePath = getMetadataPath(lingoConfig);\n const isDev = lingoConfig.environment === \"development\";\n\n logger.debug(\n `Initializing Lingo.dev compiler. Is dev mode: ${isDev}. Is main runner: ${isMainRunner()}`,\n );\n\n // Try to start up the translation server once.\n // We have two barriers, a simple one here and a more complex one inside the startTranslationServer which doesn't start the server if it can find one running.\n // We do not use isMainRunner here, because we need to start the server as early as possible, so the loaders get the translation server url. The main runner in dev mode runs after a dev server process is started.\n if (isDev && !process.env.LINGO_TRANSLATION_SERVER_URL) {\n if (lingoConfig.dev.translationServerUrl) {\n logger.info(`Using existing translation server URL (${lingoConfig.dev.translationServerUrl}) from config`);\n process.env.LINGO_TRANSLATION_SERVER_URL =\n lingoConfig.dev.translationServerUrl;\n } else {\n const translationServer = await startOrGetTranslationServer({\n translationService: new TranslationService(lingoConfig, logger),\n onError: (err) => {\n logger.error(\"Translation server error:\", err);\n },\n onReady: (port) => {\n logger.info(\n `Translation server started successfully on port: ${port}`,\n );\n },\n config: lingoConfig,\n });\n process.env.LINGO_TRANSLATION_SERVER_URL = translationServer.url;\n if (translationServer.server) {\n // We start the server in the same process, so we should be fine without any sync cleanup. Server should be killed with the process.\n registerCleanupOnCurrentProcess({\n asyncCleanup: async () => {\n await translationServer.server.stop();\n },\n });\n }\n }\n }\n\n const translationServerUrl = process.env.LINGO_TRANSLATION_SERVER_URL;\n\n if (isMainRunner()) {\n // We need to clean up the file only once to avoid having extra translation introduced into the build, or old translation to pile up.\n cleanupExistingMetadata(metadataFilePath);\n\n registerCleanupOnCurrentProcess({\n cleanup: () => cleanupExistingMetadata(metadataFilePath),\n });\n }\n\n const existingTurbopackConfig = getTurbopackConfig(nextConfig);\n let mergedRules = mergeTurbopackRules(\n existingTurbopackConfig.rules ?? {},\n Object.values(\n loaders({ lingoConfig, metadataFilePath, translationServerUrl }),\n ).map((rules) => rules.turbopack),\n );\n\n const existingResolveAlias = existingTurbopackConfig.resolveAlias;\n const mergedResolveAlias = {\n ...existingResolveAlias,\n // TODO (AleksandrSl 08/12/2025): Describe what have to be done to support custom resolvers\n };\n\n let turbopackConfig: Partial<NextConfig>;\n if (hasStableTurboConfig()) {\n turbopackConfig = {\n turbopack: {\n ...nextConfig.turbopack, // Preserve existing turbopack options\n rules: mergedRules,\n resolveAlias: mergedResolveAlias,\n },\n };\n } else {\n turbopackConfig = {\n experimental: {\n ...nextConfig.experimental, // Preserve ALL experimental options\n // @ts-expect-error - turbo for Next.js <16\n turbo: {\n // @ts-expect-error - turbo for Next.js <16\n ...nextConfig.experimental?.turbo, // Preserve existing turbo options\n rules: mergedRules,\n resolveAlias: mergedResolveAlias,\n },\n },\n };\n }\n\n const runAfterProductionCompile = async ({\n distDir,\n projectDir,\n }: {\n distDir: string;\n projectDir: string;\n }) => {\n if (typeof nextConfig.compiler?.runAfterProductionCompile === \"function\") {\n await nextConfig.compiler.runAfterProductionCompile({\n distDir,\n projectDir,\n });\n }\n\n logger.info(\"Running post-build translation generation...\");\n\n try {\n await processBuildTranslations({\n config: lingoConfig,\n publicOutputPath: distDir,\n metadataFilePath,\n });\n } catch (error) {\n logger.error(\n \"Translation generation failed:\",\n error instanceof Error ? error.message : error,\n );\n throw error;\n }\n };\n\n const webpack: NextJsWebpackConfig = (\n config: any,\n options: WebpackConfigContext,\n ) => {\n // Apply user's webpack config first if it exists\n let modifiedConfig = config;\n if (typeof nextConfig.webpack === \"function\") {\n modifiedConfig = nextConfig.webpack(config, options);\n }\n\n const lingoRules = Object.values(\n loaders({ lingoConfig, metadataFilePath, translationServerUrl }),\n )\n .map((rules) => rules.webpack)\n .filter(Boolean);\n\n // I tried using plugin from unplugin, but with all the loaders stuff it works poorly.\n // Failing with weird errors which appear on the later compilations, probably something with the cache and virtual modules\n modifiedConfig.module.rules.unshift(...lingoRules);\n\n return modifiedConfig;\n };\n\n return {\n ...nextConfig,\n ...turbopackConfig,\n compiler: {\n ...nextConfig.compiler,\n runAfterProductionCompile,\n },\n webpack,\n };\n}\n"],"mappings":"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"}
@@ -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_runtime1 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_runtime1.JSX.Element>;
10
10
  //#endregion
11
11
  export { LingoProvider };
12
12
  //# sourceMappingURL=ServerLingoProvider.d.cts.map
@@ -1,4 +1,3 @@
1
- import "react";
2
1
  import { LocaleCode } from "lingo.dev/spec";
3
2
 
4
3
  //#region src/react/shared/LingoContext.d.ts
@@ -1 +1 @@
1
- {"version":3,"file":"LingoContext.d.mts","names":[],"sources":["../../../src/react/shared/LingoContext.ts"],"sourcesContent":[],"mappings":";;;;UAGU,gBAAA;;;AAFuC;EAMjC,YAAA,EAAA,UAAA;EAKN;;;EAUM,MAAA,EAVN,UAUM;EAAM;AAwBtB;;sBA7BsB,eAAe;;;;gBAKrB;;;;;;;;;;;;;;;;;;iBAwBA,eAAA,CAAA,GAAmB"}
1
+ {"version":3,"file":"LingoContext.d.mts","names":[],"sources":["../../../src/react/shared/LingoContext.ts"],"sourcesContent":[],"mappings":";;;UAGU,gBAAA;;AAFuC;;EAWvC,YAAA,EALM,UAKN;EAKY;;;EAKA,MAAA,EAVZ,UAUY;EAwBN;;;sBA7BM,eAAe;;;;gBAKrB;;;;;;;;;;;;;;;;;;iBAwBA,eAAA,CAAA,GAAmB"}
@@ -1,5 +1,5 @@
1
1
  import { PropsWithChildren } from "react";
2
- import * as react_jsx_runtime1 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime2 from "react/jsx-runtime";
3
3
  import { LocaleCode } from "lingo.dev/spec";
4
4
 
5
5
  //#region src/react/shared/LingoProvider.d.ts
@@ -70,7 +70,7 @@ declare function LingoProvider__Dev({
70
70
  router,
71
71
  devWidget,
72
72
  children
73
- }: LingoProviderProps): react_jsx_runtime1.JSX.Element;
73
+ }: LingoProviderProps): react_jsx_runtime2.JSX.Element;
74
74
  //#endregion
75
75
  export { LingoProvider, LingoProviderProps };
76
76
  //# sourceMappingURL=LingoProvider.d.mts.map
@@ -1,5 +1,5 @@
1
1
  import { LocaleCode } from "lingo.dev/spec";
2
- import * as react_jsx_runtime1 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_runtime1.JSX.Element;
68
+ }: LocaleSwitcherProps): react_jsx_runtime3.JSX.Element;
69
69
  //#endregion
70
70
  export { LocaleSwitcher };
71
71
  //# sourceMappingURL=LocaleSwitcher.d.cts.map
@@ -1,5 +1,5 @@
1
1
  import { CSSProperties } from "react";
2
- import * as react_jsx_runtime2 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime1 from "react/jsx-runtime";
3
3
  import { LocaleCode } from "lingo.dev/spec";
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_runtime1.JSX.Element;
69
69
  //#endregion
70
70
  export { LocaleSwitcher };
71
71
  //# sourceMappingURL=LocaleSwitcher.d.mts.map
package/build/types.d.cts CHANGED
@@ -138,6 +138,9 @@ type LingoConfig = {
138
138
  * @default 60000
139
139
  */
140
140
  translationServerStartPort: number;
141
+ /**
142
+ * URL of the translation server in development mode if you manually start it
143
+ */
141
144
  translationServerUrl?: string;
142
145
  };
143
146
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.cts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;;AA4BA;AAKA;AAEA;AAEY,UA3BK,YAAA,CA2BL;EACL;;;;EAMK,IAAA,EAAA,MAAA;EAA0B;;;;EAIhC,MAAA,EAAA,MAAA;;;;;;AAHJ,KAjBU,uBAAA,GAiBV;EAAO,IAAA,EAAA,QAAA;EAUG,MAAA,EA3BoD,YA2BpC;AAK5B,CAAA;;;;AAsEwB,KAjGZ,yBAAA,GAiGY,cAAA,GAAA,eAAA;AAYF,KA3GV,mBAAA,GA2GU,aAAA,GAAA,WAAA;AAAL,KAzGL,0BAAA,GAA6B,OAyGxB,CAxGf,IAwGe,CAxGV,mBAwGU,EAAA,cAAA,CAAA,CAAA;;;;KAlGL,kBAAA,GAAqB,KAAK,aAAa,6BACjD,QACE,KACE,aACA,oCAAoC;OAE/B,QAAQ;iBACE;;KAIT,gBAAA;;;;KAKA,WAAA;;;;;;;;;;;;;;;;eAkBG;;;;;;;;;;;;;;;;;;;;gBAsBC;;;;;;;;;;;iBAYC;;;;;;;;;;;;;;;;wBAkBO;;;;;;;;;;iBAYP,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAkCD"}
1
+ {"version":3,"file":"types.d.cts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;;AA4BA;AAKA;AAEA;AAEY,UA3BK,YAAA,CA2BL;EACL;;;;EAMK,IAAA,EAAA,MAAA;EAA0B;;;;EAIhC,MAAA,EAAA,MAAA;;;;;;AAHJ,KAjBU,uBAAA,GAiBV;EAAO,IAAA,EAAA,QAAA;EAUG,MAAA,EA3BoD,YA2BpC;AAK5B,CAAA;;;;AAsEwB,KAjGZ,yBAAA,GAiGY,cAAA,GAAA,eAAA;AAYF,KA3GV,mBAAA,GA2GU,aAAA,GAAA,WAAA;AAAL,KAzGL,0BAAA,GAA6B,OAyGxB,CAxGf,IAwGe,CAxGV,mBAwGU,EAAA,cAAA,CAAA,CAAA;;;;KAlGL,kBAAA,GAAqB,KAAK,aAAa,6BACjD,QACE,KACE,aACA,oCAAoC;OAE/B,QAAQ;iBACE;;KAIT,gBAAA;;;;KAKA,WAAA;;;;;;;;;;;;;;;;eAkBG;;;;;;;;;;;;;;;;;;;;gBAsBC;;;;;;;;;;;iBAYC;;;;;;;;;;;;;;;;wBAkBO;;;;;;;;;;iBAYP,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAqCD"}
package/build/types.d.mts CHANGED
@@ -138,6 +138,9 @@ type LingoConfig = {
138
138
  * @default 60000
139
139
  */
140
140
  translationServerStartPort: number;
141
+ /**
142
+ * URL of the translation server in development mode if you manually start it
143
+ */
141
144
  translationServerUrl?: string;
142
145
  };
143
146
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;;AA4BA;AAKA;AAEA;AAEY,UA3BK,YAAA,CA2BL;EACL;;;;EAMK,IAAA,EAAA,MAAA;EAA0B;;;;EAIhC,MAAA,EAAA,MAAA;;;;;;AAHJ,KAjBU,uBAAA,GAiBV;EAAO,IAAA,EAAA,QAAA;EAUG,MAAA,EA3BoD,YA2BpC;AAK5B,CAAA;;;;AAsEwB,KAjGZ,yBAAA,GAiGY,cAAA,GAAA,eAAA;AAYF,KA3GV,mBAAA,GA2GU,aAAA,GAAA,WAAA;AAAL,KAzGL,0BAAA,GAA6B,OAyGxB,CAxGf,IAwGe,CAxGV,mBAwGU,EAAA,cAAA,CAAA,CAAA;;;;KAlGL,kBAAA,GAAqB,KAAK,aAAa,6BACjD,QACE,KACE,aACA,oCAAoC;OAE/B,QAAQ;iBACE;;KAIT,gBAAA;;;;KAKA,WAAA;;;;;;;;;;;;;;;;eAkBG;;;;;;;;;;;;;;;;;;;;gBAsBC;;;;;;;;;;;iBAYC;;;;;;;;;;;;;;;;wBAkBO;;;;;;;;;;iBAYP,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAkCD"}
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;;AA4BA;AAKA;AAEA;AAEY,UA3BK,YAAA,CA2BL;EACL;;;;EAMK,IAAA,EAAA,MAAA;EAA0B;;;;EAIhC,MAAA,EAAA,MAAA;;;;;;AAHJ,KAjBU,uBAAA,GAiBV;EAAO,IAAA,EAAA,QAAA;EAUG,MAAA,EA3BoD,YA2BpC;AAK5B,CAAA;;;;AAsEwB,KAjGZ,yBAAA,GAiGY,cAAA,GAAA,eAAA;AAYF,KA3GV,mBAAA,GA2GU,aAAA,GAAA,WAAA;AAAL,KAzGL,0BAAA,GAA6B,OAyGxB,CAxGf,IAwGe,CAxGV,mBAwGU,EAAA,cAAA,CAAA,CAAA;;;;KAlGL,kBAAA,GAAqB,KAAK,aAAa,6BACjD,QACE,KACE,aACA,oCAAoC;OAE/B,QAAQ;iBACE;;KAIT,gBAAA;;;;KAKA,WAAA;;;;;;;;;;;;;;;;eAkBG;;;;;;;;;;;;;;;;;;;;gBAsBC;;;;;;;;;;;iBAYC;;;;;;;;;;;;;;;;wBAkBO;;;;;;;;;;iBAYP,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAqCD"}
@@ -46,30 +46,39 @@ function inferPluralizationModel(models, sourceLocale, targetLocales) {
46
46
  *
47
47
  */
48
48
  function createLingoConfig(options) {
49
+ const cleanOptions = { ...options };
50
+ const cleanObject = (obj) => {
51
+ if (!obj || typeof obj !== "object") return;
52
+ Object.keys(obj).forEach((key) => {
53
+ if (obj[key] === void 0) delete obj[key];
54
+ else if (obj[key] && typeof obj[key] === "object" && !Array.isArray(obj[key])) cleanObject(obj[key]);
55
+ });
56
+ };
57
+ cleanObject(cleanOptions);
49
58
  const config = {
50
59
  ...DEFAULT_CONFIG,
51
- ...options,
52
- environment: options.environment ?? (process.env.NODE_ENV === "development" ? "development" : "production"),
53
- cacheType: options.cacheType ?? "local",
60
+ ...cleanOptions,
61
+ environment: cleanOptions.environment ?? (process.env.NODE_ENV === "development" ? "development" : "production"),
62
+ cacheType: cleanOptions.cacheType ?? "local",
54
63
  dev: {
55
64
  ...DEFAULT_CONFIG.dev,
56
- ...options.dev
65
+ ...cleanOptions.dev
57
66
  },
58
67
  pluralization: {
59
68
  ...DEFAULT_CONFIG.pluralization,
60
- ...options.pluralization
69
+ ...cleanOptions.pluralization
61
70
  },
62
71
  localePersistence: {
63
72
  ...DEFAULT_CONFIG.localePersistence,
64
- ...options.localePersistence,
73
+ ...cleanOptions.localePersistence,
65
74
  config: {
66
75
  ...DEFAULT_CONFIG.localePersistence.config,
67
- ...options.localePersistence?.config
76
+ ...cleanOptions.localePersistence?.config
68
77
  }
69
78
  }
70
79
  };
71
- const explicitEnabled = options.pluralization?.enabled;
72
- const explicitModel = options.pluralization?.model;
80
+ const explicitEnabled = cleanOptions.pluralization?.enabled;
81
+ const explicitModel = cleanOptions.pluralization?.model;
73
82
  const hasExplicitModel = typeof explicitModel === "string" && explicitModel.trim().length > 0;
74
83
  const pluralizationEnabled = typeof explicitEnabled === "boolean" ? explicitEnabled : hasExplicitModel;
75
84
  let pluralizationModel = hasExplicitModel ? explicitModel.trim() : config.pluralization.model;
@@ -45,30 +45,39 @@ function inferPluralizationModel(models, sourceLocale, targetLocales) {
45
45
  *
46
46
  */
47
47
  function createLingoConfig(options) {
48
+ const cleanOptions = { ...options };
49
+ const cleanObject = (obj) => {
50
+ if (!obj || typeof obj !== "object") return;
51
+ Object.keys(obj).forEach((key) => {
52
+ if (obj[key] === void 0) delete obj[key];
53
+ else if (obj[key] && typeof obj[key] === "object" && !Array.isArray(obj[key])) cleanObject(obj[key]);
54
+ });
55
+ };
56
+ cleanObject(cleanOptions);
48
57
  const config = {
49
58
  ...DEFAULT_CONFIG,
50
- ...options,
51
- environment: options.environment ?? (process.env.NODE_ENV === "development" ? "development" : "production"),
52
- cacheType: options.cacheType ?? "local",
59
+ ...cleanOptions,
60
+ environment: cleanOptions.environment ?? (process.env.NODE_ENV === "development" ? "development" : "production"),
61
+ cacheType: cleanOptions.cacheType ?? "local",
53
62
  dev: {
54
63
  ...DEFAULT_CONFIG.dev,
55
- ...options.dev
64
+ ...cleanOptions.dev
56
65
  },
57
66
  pluralization: {
58
67
  ...DEFAULT_CONFIG.pluralization,
59
- ...options.pluralization
68
+ ...cleanOptions.pluralization
60
69
  },
61
70
  localePersistence: {
62
71
  ...DEFAULT_CONFIG.localePersistence,
63
- ...options.localePersistence,
72
+ ...cleanOptions.localePersistence,
64
73
  config: {
65
74
  ...DEFAULT_CONFIG.localePersistence.config,
66
- ...options.localePersistence?.config
75
+ ...cleanOptions.localePersistence?.config
67
76
  }
68
77
  }
69
78
  };
70
- const explicitEnabled = options.pluralization?.enabled;
71
- const explicitModel = options.pluralization?.model;
79
+ const explicitEnabled = cleanOptions.pluralization?.enabled;
80
+ const explicitModel = cleanOptions.pluralization?.model;
72
81
  const hasExplicitModel = typeof explicitModel === "string" && explicitModel.trim().length > 0;
73
82
  const pluralizationEnabled = typeof explicitEnabled === "boolean" ? explicitEnabled : hasExplicitModel;
74
83
  let pluralizationModel = hasExplicitModel ? explicitModel.trim() : config.pluralization.model;
@@ -1 +1 @@
1
- {"version":3,"file":"config-factory.mjs","names":["config: LingoConfig"],"sources":["../../src/utils/config-factory.ts"],"sourcesContent":["/**\n * Config factory for creating LoaderConfig instances\n */\nimport type {\n LingoConfig,\n LingoConfigRequiredFields,\n LingoInternalFields,\n PartialLingoConfig,\n} from \"../types\";\n\n/**\n * Default configuration values\n */\nexport const DEFAULT_CONFIG = {\n sourceRoot: \"src\",\n lingoDir: \"lingo\",\n useDirective: false,\n dev: {\n translationServerStartPort: 60000,\n },\n localePersistence: {\n type: \"cookie\" as const,\n config: {\n name: \"locale\",\n maxAge: 31536000,\n },\n },\n models: \"lingo.dev\",\n pluralization: {\n enabled: false,\n model: \"groq:llama-3.1-8b-instant\",\n },\n buildMode: \"translate\",\n} satisfies Omit<\n LingoConfig,\n // Looks like we can use LingoInternalFields, but it's only a coincidence that the types match, we may want to provide default for internal fields\n LingoConfigRequiredFields | \"environment\" | \"cacheType\"\n>;\n\nfunction getModelStringForLocales(\n models: Record<string, string>,\n sourceLocale: string,\n targetLocale: string | undefined,\n): string | undefined {\n const localeKeys = targetLocale\n ? [\n `${sourceLocale}:${targetLocale}`,\n `*:${targetLocale}`,\n `${sourceLocale}:*`,\n \"*:*\",\n ]\n : [`${sourceLocale}:*`, \"*:*\"];\n\n const modelKey = localeKeys.find((key) => key in models);\n if (modelKey) {\n return models[modelKey];\n }\n\n const sortedKeys = Object.keys(models).sort();\n if (sortedKeys.length === 0) {\n return undefined;\n }\n\n return models[sortedKeys[0]];\n}\n\nfunction inferPluralizationModel(\n models: \"lingo.dev\" | Record<string, string>,\n sourceLocale: string,\n targetLocales: string[],\n): string | undefined {\n if (models === \"lingo.dev\") {\n return undefined;\n }\n\n return getModelStringForLocales(\n models,\n sourceLocale,\n targetLocales[0],\n );\n}\n\n/**\n * Create a LoaderConfig with defaults applied\n *\n * @param options - Partial config to override defaults\n * @returns Complete LoaderConfig with all defaults applied\n *\n */\nexport function createLingoConfig(\n options: PartialLingoConfig & Partial<Pick<LingoConfig, LingoInternalFields>>,\n): LingoConfig {\n const config: LingoConfig = {\n ...DEFAULT_CONFIG,\n ...options,\n environment:\n options.environment ??\n (process.env.NODE_ENV === \"development\" ? \"development\" : \"production\"),\n cacheType: options.cacheType ?? \"local\",\n dev: {\n ...DEFAULT_CONFIG.dev,\n ...options.dev,\n },\n pluralization: {\n ...DEFAULT_CONFIG.pluralization,\n ...options.pluralization,\n },\n localePersistence: {\n ...DEFAULT_CONFIG.localePersistence,\n ...options.localePersistence,\n config: {\n ...DEFAULT_CONFIG.localePersistence.config,\n ...options.localePersistence?.config,\n },\n },\n };\n\n const explicitEnabled = options.pluralization?.enabled;\n const explicitModel = options.pluralization?.model;\n const hasExplicitModel =\n typeof explicitModel === \"string\" && explicitModel.trim().length > 0;\n const hasExplicitEnabled = typeof explicitEnabled === \"boolean\";\n\n const pluralizationEnabled = hasExplicitEnabled\n ? explicitEnabled\n : hasExplicitModel;\n\n let pluralizationModel = hasExplicitModel\n ? explicitModel!.trim()\n : config.pluralization.model;\n\n if (pluralizationEnabled && !hasExplicitModel) {\n const inferredModel = inferPluralizationModel(\n config.models,\n config.sourceLocale,\n config.targetLocales,\n );\n\n if (!inferredModel) {\n throw new Error(\n 'Pluralization is enabled but no \"pluralization.model\" is configured. Please set \"pluralization.model\" explicitly or use direct LLM models (not \"lingo.dev\") so the model can be inferred.',\n );\n }\n\n pluralizationModel = inferredModel;\n }\n\n config.pluralization = {\n ...config.pluralization,\n enabled: pluralizationEnabled,\n model: pluralizationModel,\n };\n\n return config;\n}\n"],"mappings":";;;;AAaA,MAAa,iBAAiB;CAC5B,YAAY;CACZ,UAAU;CACV,cAAc;CACd,KAAK,EACH,4BAA4B,KAC7B;CACD,mBAAmB;EACjB,MAAM;EACN,QAAQ;GACN,MAAM;GACN,QAAQ;GACT;EACF;CACD,QAAQ;CACR,eAAe;EACb,SAAS;EACT,OAAO;EACR;CACD,WAAW;CACZ;AAMD,SAAS,yBACP,QACA,cACA,cACoB;CAUpB,MAAM,YATa,eACf;EACE,GAAG,aAAa,GAAG;EACnB,KAAK;EACL,GAAG,aAAa;EAChB;EACD,GACD,CAAC,GAAG,aAAa,KAAK,MAAM,EAEJ,MAAM,QAAQ,OAAO,OAAO;AACxD,KAAI,SACF,QAAO,OAAO;CAGhB,MAAM,aAAa,OAAO,KAAK,OAAO,CAAC,MAAM;AAC7C,KAAI,WAAW,WAAW,EACxB;AAGF,QAAO,OAAO,WAAW;;AAG3B,SAAS,wBACP,QACA,cACA,eACoB;AACpB,KAAI,WAAW,YACb;AAGF,QAAO,yBACL,QACA,cACA,cAAc,GACf;;;;;;;;;AAUH,SAAgB,kBACd,SACa;CACb,MAAMA,SAAsB;EAC1B,GAAG;EACH,GAAG;EACH,aACE,QAAQ,gBACP,QAAQ,IAAI,aAAa,gBAAgB,gBAAgB;EAC5D,WAAW,QAAQ,aAAa;EAChC,KAAK;GACH,GAAG,eAAe;GAClB,GAAG,QAAQ;GACZ;EACD,eAAe;GACb,GAAG,eAAe;GAClB,GAAG,QAAQ;GACZ;EACD,mBAAmB;GACjB,GAAG,eAAe;GAClB,GAAG,QAAQ;GACX,QAAQ;IACN,GAAG,eAAe,kBAAkB;IACpC,GAAG,QAAQ,mBAAmB;IAC/B;GACF;EACF;CAED,MAAM,kBAAkB,QAAQ,eAAe;CAC/C,MAAM,gBAAgB,QAAQ,eAAe;CAC7C,MAAM,mBACJ,OAAO,kBAAkB,YAAY,cAAc,MAAM,CAAC,SAAS;CAGrE,MAAM,uBAFqB,OAAO,oBAAoB,YAGlD,kBACA;CAEJ,IAAI,qBAAqB,mBACrB,cAAe,MAAM,GACrB,OAAO,cAAc;AAEzB,KAAI,wBAAwB,CAAC,kBAAkB;EAC7C,MAAM,gBAAgB,wBACpB,OAAO,QACP,OAAO,cACP,OAAO,cACR;AAED,MAAI,CAAC,cACH,OAAM,IAAI,MACR,kMACD;AAGH,uBAAqB;;AAGvB,QAAO,gBAAgB;EACrB,GAAG,OAAO;EACV,SAAS;EACT,OAAO;EACR;AAED,QAAO"}
1
+ {"version":3,"file":"config-factory.mjs","names":["config: LingoConfig"],"sources":["../../src/utils/config-factory.ts"],"sourcesContent":["/**\n * Config factory for creating LoaderConfig instances\n */\nimport type {\n LingoConfig,\n LingoConfigRequiredFields,\n LingoInternalFields,\n PartialLingoConfig,\n} from \"../types\";\n\n/**\n * Default configuration values\n */\nexport const DEFAULT_CONFIG = {\n sourceRoot: \"src\",\n lingoDir: \"lingo\",\n useDirective: false,\n dev: {\n translationServerStartPort: 60000,\n },\n localePersistence: {\n type: \"cookie\" as const,\n config: {\n name: \"locale\",\n maxAge: 31536000,\n },\n },\n models: \"lingo.dev\",\n pluralization: {\n enabled: false,\n model: \"groq:llama-3.1-8b-instant\",\n },\n buildMode: \"translate\",\n} satisfies Omit<\n LingoConfig,\n // Looks like we can use LingoInternalFields, but it's only a coincidence that the types match, we may want to provide default for internal fields\n LingoConfigRequiredFields | \"environment\" | \"cacheType\"\n>;\n\nfunction getModelStringForLocales(\n models: Record<string, string>,\n sourceLocale: string,\n targetLocale: string | undefined,\n): string | undefined {\n const localeKeys = targetLocale\n ? [\n `${sourceLocale}:${targetLocale}`,\n `*:${targetLocale}`,\n `${sourceLocale}:*`,\n \"*:*\",\n ]\n : [`${sourceLocale}:*`, \"*:*\"];\n\n const modelKey = localeKeys.find((key) => key in models);\n if (modelKey) {\n return models[modelKey];\n }\n\n const sortedKeys = Object.keys(models).sort();\n if (sortedKeys.length === 0) {\n return undefined;\n }\n\n return models[sortedKeys[0]];\n}\n\nfunction inferPluralizationModel(\n models: \"lingo.dev\" | Record<string, string>,\n sourceLocale: string,\n targetLocales: string[],\n): string | undefined {\n if (models === \"lingo.dev\") {\n return undefined;\n }\n\n return getModelStringForLocales(\n models,\n sourceLocale,\n targetLocales[0],\n );\n}\n\n/**\n * Create a LoaderConfig with defaults applied\n *\n * @param options - Partial config to override defaults\n * @returns Complete LoaderConfig with all defaults applied\n *\n */\nexport function createLingoConfig(\n options: PartialLingoConfig & Partial<Pick<LingoConfig, LingoInternalFields>>,\n): LingoConfig {\n const cleanOptions = { ...options };\n\n const cleanObject = (obj: any) => {\n if (!obj || typeof obj !== \"object\") return;\n Object.keys(obj).forEach((key) => {\n if (obj[key] === undefined) {\n delete obj[key];\n } else if (\n obj[key] &&\n typeof obj[key] === \"object\" &&\n !Array.isArray(obj[key])\n ) {\n cleanObject(obj[key]);\n }\n });\n };\n\n cleanObject(cleanOptions);\n\n const config: LingoConfig = {\n ...DEFAULT_CONFIG,\n ...cleanOptions,\n environment:\n cleanOptions.environment ??\n (process.env.NODE_ENV === \"development\" ? \"development\" : \"production\"),\n cacheType: cleanOptions.cacheType ?? \"local\",\n dev: {\n ...DEFAULT_CONFIG.dev,\n ...cleanOptions.dev,\n },\n pluralization: {\n ...DEFAULT_CONFIG.pluralization,\n ...cleanOptions.pluralization,\n },\n localePersistence: {\n ...DEFAULT_CONFIG.localePersistence,\n ...cleanOptions.localePersistence,\n config: {\n ...DEFAULT_CONFIG.localePersistence.config,\n ...cleanOptions.localePersistence?.config,\n },\n },\n };\n\n const explicitEnabled = cleanOptions.pluralization?.enabled;\n const explicitModel = cleanOptions.pluralization?.model;\n const hasExplicitModel =\n typeof explicitModel === \"string\" && explicitModel.trim().length > 0;\n const hasExplicitEnabled = typeof explicitEnabled === \"boolean\";\n\n const pluralizationEnabled = hasExplicitEnabled\n ? explicitEnabled\n : hasExplicitModel;\n\n let pluralizationModel = hasExplicitModel\n ? explicitModel!.trim()\n : config.pluralization.model;\n\n if (pluralizationEnabled && !hasExplicitModel) {\n const inferredModel = inferPluralizationModel(\n config.models,\n config.sourceLocale,\n config.targetLocales,\n );\n\n if (!inferredModel) {\n throw new Error(\n 'Pluralization is enabled but no \"pluralization.model\" is configured. Please set \"pluralization.model\" explicitly or use direct LLM models (not \"lingo.dev\") so the model can be inferred.',\n );\n }\n\n pluralizationModel = inferredModel;\n }\n\n config.pluralization = {\n ...config.pluralization,\n enabled: pluralizationEnabled,\n model: pluralizationModel,\n };\n\n return config;\n}\n"],"mappings":";;;;AAaA,MAAa,iBAAiB;CAC5B,YAAY;CACZ,UAAU;CACV,cAAc;CACd,KAAK,EACH,4BAA4B,KAC7B;CACD,mBAAmB;EACjB,MAAM;EACN,QAAQ;GACN,MAAM;GACN,QAAQ;GACT;EACF;CACD,QAAQ;CACR,eAAe;EACb,SAAS;EACT,OAAO;EACR;CACD,WAAW;CACZ;AAMD,SAAS,yBACP,QACA,cACA,cACoB;CAUpB,MAAM,YATa,eACf;EACE,GAAG,aAAa,GAAG;EACnB,KAAK;EACL,GAAG,aAAa;EAChB;EACD,GACD,CAAC,GAAG,aAAa,KAAK,MAAM,EAEJ,MAAM,QAAQ,OAAO,OAAO;AACxD,KAAI,SACF,QAAO,OAAO;CAGhB,MAAM,aAAa,OAAO,KAAK,OAAO,CAAC,MAAM;AAC7C,KAAI,WAAW,WAAW,EACxB;AAGF,QAAO,OAAO,WAAW;;AAG3B,SAAS,wBACP,QACA,cACA,eACoB;AACpB,KAAI,WAAW,YACb;AAGF,QAAO,yBACL,QACA,cACA,cAAc,GACf;;;;;;;;;AAUH,SAAgB,kBACd,SACa;CACb,MAAM,eAAe,EAAE,GAAG,SAAS;CAEnC,MAAM,eAAe,QAAa;AAChC,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU;AACrC,SAAO,KAAK,IAAI,CAAC,SAAS,QAAQ;AAChC,OAAI,IAAI,SAAS,OACf,QAAO,IAAI;YAEX,IAAI,QACJ,OAAO,IAAI,SAAS,YACpB,CAAC,MAAM,QAAQ,IAAI,KAAK,CAExB,aAAY,IAAI,KAAK;IAEvB;;AAGJ,aAAY,aAAa;CAEzB,MAAMA,SAAsB;EAC1B,GAAG;EACH,GAAG;EACH,aACE,aAAa,gBACZ,QAAQ,IAAI,aAAa,gBAAgB,gBAAgB;EAC5D,WAAW,aAAa,aAAa;EACrC,KAAK;GACH,GAAG,eAAe;GAClB,GAAG,aAAa;GACjB;EACD,eAAe;GACb,GAAG,eAAe;GAClB,GAAG,aAAa;GACjB;EACD,mBAAmB;GACjB,GAAG,eAAe;GAClB,GAAG,aAAa;GAChB,QAAQ;IACN,GAAG,eAAe,kBAAkB;IACpC,GAAG,aAAa,mBAAmB;IACpC;GACF;EACF;CAED,MAAM,kBAAkB,aAAa,eAAe;CACpD,MAAM,gBAAgB,aAAa,eAAe;CAClD,MAAM,mBACJ,OAAO,kBAAkB,YAAY,cAAc,MAAM,CAAC,SAAS;CAGrE,MAAM,uBAFqB,OAAO,oBAAoB,YAGlD,kBACA;CAEJ,IAAI,qBAAqB,mBACrB,cAAe,MAAM,GACrB,OAAO,cAAc;AAEzB,KAAI,wBAAwB,CAAC,kBAAkB;EAC7C,MAAM,gBAAgB,wBACpB,OAAO,QACP,OAAO,cACP,OAAO,cACR;AAED,MAAI,CAAC,cACH,OAAM,IAAI,MACR,kMACD;AAGH,uBAAqB;;AAGvB,QAAO,gBAAgB;EACrB,GAAG,OAAO;EACV,SAAS;EACT,OAAO;EACR;AAED,QAAO"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lingo.dev/compiler",
3
- "version": "0.3.10",
3
+ "version": "0.3.12",
4
4
  "description": "Lingo.dev Compiler",
5
5
  "private": false,
6
6
  "repository": {
@@ -161,7 +161,7 @@
161
161
  "posthog-node": "5.14.0",
162
162
  "lmdb": "3.2.6",
163
163
  "ws": "8.18.3",
164
- "lingo.dev": "^0.132.2"
164
+ "lingo.dev": "^0.132.9"
165
165
  },
166
166
  "peerDependencies": {
167
167
  "next": "^15.0.0 || ^16.0.4",