@the-i18n-kit/cli 6.0.0 → 8.0.0

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.
Files changed (91) hide show
  1. package/README.md +7 -57
  2. package/dist/bin.js +1 -1
  3. package/dist/{_shared-CkMAydRl.js → cli-BTMcWXGs.js} +157 -27
  4. package/dist/cli-BTMcWXGs.js.map +1 -0
  5. package/dist/config/framework/stubs/{next-intl-routing-lExp4Q3r.d.ts → next-intl-routing-i6Mlxwdt.d.ts} +1 -1
  6. package/dist/config/framework/stubs/{next-intl-routing-lExp4Q3r.d.ts.map → next-intl-routing-i6Mlxwdt.d.ts.map} +1 -1
  7. package/dist/{define-config-BeHvSYBP.d.ts → define-config-BpdVaEVR.d.ts} +1 -1
  8. package/dist/{define-config-DW-rgsU6.d.ts → define-config-ZRZw5PWy.d.ts} +40 -6
  9. package/dist/define-config-ZRZw5PWy.d.ts.map +1 -0
  10. package/dist/define-config.d.ts +1 -1
  11. package/dist/descriptors-Bo5UM031.js +1242 -0
  12. package/dist/descriptors-Bo5UM031.js.map +1 -0
  13. package/dist/detector-B4z_RZde.js +2189 -0
  14. package/dist/detector-B4z_RZde.js.map +1 -0
  15. package/dist/detector-DTfFbwSU.js +5 -0
  16. package/dist/{index-w-EQZEZF.d.ts → index-CWFWYHf5.d.ts} +728 -268
  17. package/dist/index-CWFWYHf5.d.ts.map +1 -0
  18. package/dist/index.d.ts +1 -1
  19. package/dist/index.js +8 -4
  20. package/dist/json-writer-D0b6vEax.js +2 -0
  21. package/dist/json-writer-ek8yEI5R.js +342 -0
  22. package/dist/json-writer-ek8yEI5R.js.map +1 -0
  23. package/dist/operations-CKHEmLNJ.js +8 -0
  24. package/dist/{operations-PfRSTepi.js → operations-Daf2Ommm.js} +1655 -3298
  25. package/dist/operations-Daf2Ommm.js.map +1 -0
  26. package/dist/php-reader-BGx6Ii2d.js +2 -0
  27. package/dist/{php-reader-3Fgw80zK.js → php-reader-DRpcRVzv.js} +6 -3
  28. package/dist/{php-reader-3Fgw80zK.js.map → php-reader-DRpcRVzv.js.map} +1 -1
  29. package/dist/{providers-CAsU_aV1.js → project-config-eLR0J377.js} +24 -209
  30. package/dist/project-config-eLR0J377.js.map +1 -0
  31. package/dist/providers-BbVPelvp.js +406 -0
  32. package/dist/providers-BbVPelvp.js.map +1 -0
  33. package/dist/report-By1-5JtO.js +37 -0
  34. package/dist/report-By1-5JtO.js.map +1 -0
  35. package/dist/report-CHZgH9Wy.js +2 -0
  36. package/package.json +4 -16
  37. package/dist/_shared-CkMAydRl.js.map +0 -1
  38. package/dist/add-BBoVUNEq.js +0 -40
  39. package/dist/add-BBoVUNEq.js.map +0 -1
  40. package/dist/check-IosaN_EM.js +0 -41
  41. package/dist/check-IosaN_EM.js.map +0 -1
  42. package/dist/cli-CnZNGUGu.js +0 -70
  43. package/dist/cli-CnZNGUGu.js.map +0 -1
  44. package/dist/config/framework/stubs/unplugin-vue-i18n-mH7YdYqA.d.ts +0 -25
  45. package/dist/config/framework/stubs/unplugin-vue-i18n-mH7YdYqA.d.ts.map +0 -1
  46. package/dist/config/framework/stubs/unplugin-vue-i18n.js +0 -26
  47. package/dist/config/framework/stubs/unplugin-vue-i18n.js.map +0 -1
  48. package/dist/define-config-DW-rgsU6.d.ts.map +0 -1
  49. package/dist/detect-3jjcQJs1.js +0 -17
  50. package/dist/detect-3jjcQJs1.js.map +0 -1
  51. package/dist/empty-D3La0enO.js +0 -36
  52. package/dist/empty-D3La0enO.js.map +0 -1
  53. package/dist/find-duplicates-BlQoJDgu.js +0 -42
  54. package/dist/find-duplicates-BlQoJDgu.js.map +0 -1
  55. package/dist/get-Cr5O5zJX.js +0 -41
  56. package/dist/get-Cr5O5zJX.js.map +0 -1
  57. package/dist/index-w-EQZEZF.d.ts.map +0 -1
  58. package/dist/init-BRBMkcI0.js +0 -33
  59. package/dist/init-BRBMkcI0.js.map +0 -1
  60. package/dist/list-dirs-BMuByyuX.js +0 -17
  61. package/dist/list-dirs-BMuByyuX.js.map +0 -1
  62. package/dist/missing-CBOk4ZgD.js +0 -51
  63. package/dist/missing-CBOk4ZgD.js.map +0 -1
  64. package/dist/move-DOdPKnOV.js +0 -50
  65. package/dist/move-DOdPKnOV.js.map +0 -1
  66. package/dist/operations-PfRSTepi.js.map +0 -1
  67. package/dist/php-reader-CpnaPSpZ.js +0 -2
  68. package/dist/providers-CAsU_aV1.js.map +0 -1
  69. package/dist/remove-CVBjJV9h.js +0 -41
  70. package/dist/remove-CVBjJV9h.js.map +0 -1
  71. package/dist/remove-orphans-BaKEISxA.js +0 -57
  72. package/dist/remove-orphans-BaKEISxA.js.map +0 -1
  73. package/dist/rename-CN2ajUeb.js +0 -45
  74. package/dist/rename-CN2ajUeb.js.map +0 -1
  75. package/dist/scaffold-CUKUFuEy.js +0 -39
  76. package/dist/scaffold-CUKUFuEy.js.map +0 -1
  77. package/dist/scan-Bhv0Nmy3.js +0 -31
  78. package/dist/scan-Bhv0Nmy3.js.map +0 -1
  79. package/dist/search-CrkLgz3m.js +0 -49
  80. package/dist/search-CrkLgz3m.js.map +0 -1
  81. package/dist/status-DprS-qDC.js +0 -45
  82. package/dist/status-DprS-qDC.js.map +0 -1
  83. package/dist/translate-Cs6EdbzA.js +0 -92
  84. package/dist/translate-Cs6EdbzA.js.map +0 -1
  85. package/dist/translate-key-BBZpYQjL.js +0 -73
  86. package/dist/translate-key-BBZpYQjL.js.map +0 -1
  87. package/dist/update-BQuGxSSy.js +0 -40
  88. package/dist/update-BQuGxSSy.js.map +0 -1
  89. package/dist/write-B8z6I5Vf.js +0 -47
  90. package/dist/write-B8z6I5Vf.js.map +0 -1
  91. /package/dist/{bin-g05vSfAz.d.ts → bin-NyzIHE2F.d.ts} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detector-B4z_RZde.js","names":["NUXT_CONFIG_FILES","SKIP_DIRS","COMMON_LOCALE_DIRS","findLocaleDir","discoverLocales","NEXT_CONFIG_FILES"],"sources":["../src/io/php-writer.ts","../src/io/yaml-reader.ts","../src/io/yaml-writer.ts","../src/io/formats.ts","../src/adapters/registry.ts","../src/config/paths.ts","../src/config/locale-override.ts","../src/config/fallback-locale.ts","../src/adapters/nuxt/discovery.ts","../src/adapters/nuxt/kit-loader.ts","../src/adapters/nuxt/layer-dedup.ts","../src/adapters/nuxt/artifact.ts","../src/adapters/nuxt/merge-apps.ts","../src/adapters/nuxt/index.ts","../src/adapters/laravel/index.ts","../src/adapters/generic/index.ts","../src/config/framework/execute.ts","../src/config/framework/next.ts","../src/adapters/shared.ts","../src/adapters/react/index.ts","../src/config/cache.ts","../src/config/workspace-graph.ts","../src/config/detector.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises'\nimport { FileIOError } from '../utils/errors'\nimport { toErrorMessage } from '../utils/errors'\nimport { sortKeysDeep, orderKeysPreserving } from './key-operations'\nimport { clearPhpFileCacheEntry } from './php-reader'\nimport { atomicWrite } from './atomic-write'\n\nexport interface PhpWriteOptions {\n quoteStyle?: 'single' | 'double'\n indent?: string\n sortKeys?: boolean\n}\n\nexport async function writePhpLocaleFile(\n filePath: string,\n data: Record<string, unknown>,\n options: PhpWriteOptions = {},\n): Promise<void> {\n const {\n quoteStyle = 'double',\n indent = ' ',\n sortKeys = true,\n } = options\n\n try {\n const outputData = sortKeys ? sortKeysDeep(data) : data\n const content = serializePhpArray(outputData, quoteStyle, indent)\n\n await atomicWrite(filePath, content, () => clearPhpFileCacheEntry(filePath))\n }\n catch (error) {\n if (error instanceof FileIOError) throw error\n throw new FileIOError(\n `Failed to write PHP locale file: ${filePath}: ${toErrorMessage(error)}`,\n filePath,\n )\n }\n}\n\nfunction serializePhpArray(\n data: Record<string, unknown>,\n quoteStyle: 'single' | 'double',\n indent: string,\n): string {\n const q = quoteStyle === 'single' ? '\\'' : '\"'\n const lines: string[] = ['<?php', '', 'return [']\n\n renderEntries(data, lines, q, indent, 1)\n\n lines.push('];', '')\n return lines.join('\\n')\n}\n\nfunction renderEntries(\n obj: Record<string, unknown>,\n lines: string[],\n q: string,\n indent: string,\n depth: number,\n): void {\n const prefix = indent.repeat(depth)\n const entries = Object.entries(obj)\n\n for (const [key, value] of entries) {\n const escapedKey = escapePhpString(key, q)\n const keyPart = `${prefix}${q}${escapedKey}${q}`\n\n if (value === null) {\n lines.push(`${keyPart} => null,`)\n }\n else if (typeof value === 'boolean') {\n lines.push(`${keyPart} => ${value ? 'true' : 'false'},`)\n }\n else if (typeof value === 'number') {\n lines.push(`${keyPart} => ${value},`)\n }\n else if (Array.isArray(value)) {\n lines.push(`${keyPart} => [`)\n renderArray(value, lines, q, indent, depth + 1)\n lines.push(`${prefix}],`)\n }\n else if (typeof value === 'object') {\n lines.push(`${keyPart} => [`)\n renderEntries(value as Record<string, unknown>, lines, q, indent, depth + 1)\n lines.push(`${prefix}],`)\n }\n else {\n const escapedValue = escapePhpString(String(value), q)\n lines.push(`${keyPart} => ${q}${escapedValue}${q},`)\n }\n }\n}\n\nfunction escapePhpString(str: string, quote: string): string {\n if (quote === '\\'') {\n return str.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, '\\\\\\'')\n }\n // Double-quoted PHP strings interpolate variables: an unescaped `$` (or\n // `{$…}`) in a value would become live PHP interpolation on read-back.\n return str.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"').replace(/\\$/g, '\\\\$')\n}\n\nfunction renderArray(\n arr: unknown[],\n lines: string[],\n q: string,\n indent: string,\n depth: number,\n): void {\n const prefix = indent.repeat(depth)\n for (const value of arr) {\n if (value === null) {\n lines.push(`${prefix}null,`)\n }\n else if (typeof value === 'boolean') {\n lines.push(`${prefix}${value ? 'true' : 'false'},`)\n }\n else if (typeof value === 'number') {\n lines.push(`${prefix}${value},`)\n }\n else if (Array.isArray(value)) {\n lines.push(`${prefix}[`)\n renderArray(value, lines, q, indent, depth + 1)\n lines.push(`${prefix}],`)\n }\n else if (typeof value === 'object') {\n lines.push(`${prefix}[`)\n renderEntries(value as Record<string, unknown>, lines, q, indent, depth + 1)\n lines.push(`${prefix}],`)\n }\n else {\n const escaped = escapePhpString(String(value), q)\n lines.push(`${prefix}${q}${escaped}${q},`)\n }\n }\n}\n\nexport function detectPhpStyle(content: string): { quoteStyle: 'single' | 'double'; indent: string } {\n const keyPattern = /(['\"])([^'\"]+)\\1\\s*=>/g\n let singleCount = 0\n let doubleCount = 0\n let match: RegExpExecArray | null\n while ((match = keyPattern.exec(content)) !== null) {\n if (match[1] === '\\'') singleCount++\n else doubleCount++\n }\n const quoteStyle: 'single' | 'double' = singleCount > doubleCount ? 'single' : 'double'\n\n const indent = content.match(/^([ \\t]+)['\"]/m)?.[1] ?? ' '\n\n return { quoteStyle, indent }\n}\n\n/**\n * Read, mutate, and write back a single PHP locale file while preserving its\n * existing style (quote style + indentation, via detectPhpStyle) and key\n * order: existing keys keep their on-disk order; keys added by the mutation\n * are inserted in sorted position among their siblings.\n */\nexport async function mutatePhpLocaleFile(\n filePath: string,\n mutate: (data: Record<string, unknown>) => void,\n): Promise<void> {\n const { readPhpLocaleFile } = await import('./php-reader.js')\n const data = await readPhpLocaleFile(filePath)\n const rawContent = await readFile(filePath, 'utf-8')\n const { quoteStyle, indent } = detectPhpStyle(rawContent)\n // Snapshot the on-disk key order before the mutation runs.\n const reference = structuredClone(data)\n mutate(data)\n const ordered = orderKeysPreserving(data, reference)\n await writePhpLocaleFile(filePath, ordered, { quoteStyle, indent, sortKeys: false })\n}\n","import { parseAllDocuments } from 'yaml'\nimport { FileIOError } from '../utils/errors'\nimport { createReadCache } from './read-cache'\n\n/**\n * Parse a YAML locale file into plain data.\n *\n * A locale file is one mapping, so a stream of several documents is refused by\n * name rather than silently reduced to its first one. Parse errors are\n * collected on the document rather than thrown, so the first one is raised\n * here to reach the same wrapping the JSON reader gets.\n */\nfunction parseYaml(content: string): Record<string, unknown> {\n const documents = parseAllDocuments(content)\n\n if (documents.length > 1) {\n throw new SyntaxError(\n `YAML file holds ${documents.length} documents (separated by '---') — a locale file must hold exactly one`,\n )\n }\n\n const document = documents[0]\n // An empty file parses to no document at all; the validation below rejects\n // it the way an empty .json file is rejected.\n if (!document) return null as unknown as Record<string, unknown>\n\n const error = document.errors[0]\n if (error) throw new SyntaxError(error.message)\n\n return document.toJS() as Record<string, unknown>\n}\n\nconst {\n read: readYamlLocaleFile,\n clear: clearYamlFileCache,\n clearEntry: clearYamlFileCacheEntry,\n} = createReadCache<Record<string, unknown>>(\n parseYaml,\n 'YAML',\n (parsed, filePath) => {\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new FileIOError(`YAML file must contain a mapping: ${filePath}`, filePath, 'INVALID_YAML')\n }\n },\n)\n\nexport { readYamlLocaleFile, clearYamlFileCache, clearYamlFileCacheEntry }\n","import { stringify } from 'yaml'\nimport { FileIOError, toErrorMessage } from '../utils/errors'\nimport { sortKeysDeep, orderKeysPreserving } from './key-operations'\nimport { clearYamlFileCacheEntry, readYamlLocaleFile } from './yaml-reader'\nimport { atomicWrite } from './atomic-write'\n\nexport interface YamlWriteOptions {\n sortKeys?: boolean\n}\n\n/**\n * Fixed rather than detected from the file being written: YAML has one legal\n * indent character, and `lineWidth: 0` keeps long UI strings on a single line.\n * Folded ones re-read as the same string, but every wrap point moves as soon\n * as a word changes, which turns a one-word edit into a multi-line diff.\n */\nconst STRINGIFY_OPTIONS = { indent: 2, lineWidth: 0 } as const\n\n/**\n * Comments in an existing file do not survive a write: the file is\n * re-serialized from the parsed values, not patched into the document tree\n * that carries them. Keep notes for translators in the kit config\n * (`localeNotes`) rather than in the locale files it rewrites.\n */\nexport async function writeYamlLocaleFile(\n filePath: string,\n data: Record<string, unknown>,\n options: YamlWriteOptions = {},\n): Promise<void> {\n const { sortKeys = true } = options\n\n try {\n const outputData = sortKeys ? sortKeysDeep(data) : data\n // stringify always terminates with a newline.\n const content = stringify(outputData, STRINGIFY_OPTIONS)\n\n await atomicWrite(filePath, content, () => clearYamlFileCacheEntry(filePath))\n }\n catch (error) {\n if (error instanceof FileIOError) throw error\n throw new FileIOError(\n `Failed to write YAML locale file: ${filePath}: ${toErrorMessage(error)}`,\n filePath,\n )\n }\n}\n\n/**\n * Read, mutate and write back a single YAML locale file, preserving key order:\n * existing keys keep their on-disk order and keys added by the mutation are\n * inserted in sorted position among their siblings.\n */\nexport async function mutateYamlLocaleFile(\n filePath: string,\n mutate: (data: Record<string, unknown>) => void,\n): Promise<void> {\n const data = await readYamlLocaleFile(filePath)\n // Snapshot the on-disk key order before the mutation runs.\n const reference = structuredClone(data)\n mutate(data)\n const ordered = orderKeysPreserving(data, reference)\n await writeYamlLocaleFile(filePath, ordered, { sortKeys: false })\n}\n","/**\n * One registry for everything that differs between locale file formats.\n *\n * The readers and writers used to be reachable only through\n * `if (format === 'php-array')` branches scattered across locale IO, format\n * detection, the read operations and the scaffolder, so every new format meant\n * finding all of them again. A format now declares its extensions, its IO\n * functions and the two layout facts those callers used the format id to\n * guess, and they dispatch through `getFormat` / `formatForFile` instead of\n * comparing strings.\n */\n\nimport { readdir } from 'node:fs/promises'\nimport { extname, join } from 'node:path'\nimport type { LocaleFileFormat } from '../adapters/types.js'\nimport { ConfigError, FileIOError } from '../utils/errors.js'\nimport { log } from '../utils/logger.js'\n\nimport { readLocaleFile, clearFileCache, clearFileCacheEntry } from './json-reader.js'\nimport { writeLocaleFile, mutateLocaleFile } from './json-writer.js'\nimport { readPhpLocaleFile, clearPhpFileCache, clearPhpFileCacheEntry } from './php-reader.js'\nimport { writePhpLocaleFile, mutatePhpLocaleFile } from './php-writer.js'\nimport { readYamlLocaleFile, clearYamlFileCache, clearYamlFileCacheEntry } from './yaml-reader.js'\nimport { writeYamlLocaleFile, mutateYamlLocaleFile } from './yaml-writer.js'\n\n/**\n * Write options every format understands. Per-format style (indentation,\n * quote style) is detected from the file being written, not passed in.\n */\nexport interface LocaleWriteOptions {\n sortKeys?: boolean\n}\n\n/**\n * How a layer directory is laid out when there is nothing on disk to observe.\n * 'namespaced' is Laravel's directory-per-locale with one file per namespace;\n * 'flat' is one file per locale. Layouts are read off disk wherever files\n * already exist — this is only the fallback for a layer that has none.\n */\nexport type LocaleLayout = 'flat' | 'namespaced'\n\nexport interface LocaleFormat {\n readonly id: LocaleFileFormat\n /** Recognized extensions, canonical one first — the one new files get. */\n readonly extensions: readonly string[]\n readonly defaultLayout: LocaleLayout\n /**\n * Whether a flat layout is discovered from disk rather than declared. A PHP\n * project may be namespaced or flat and only the directory says which, so\n * the flat file is guessed as `<localeCode><ext>` and confirmed to exist.\n * The adapters that resolve JSON always name the file instead, and it counts\n * even before it exists — that is what scaffolding a new locale writes.\n */\n readonly flatFileFromDisk: boolean\n read(filePath: string): Promise<Record<string, unknown>>\n write(filePath: string, data: Record<string, unknown>, options?: LocaleWriteOptions): Promise<void>\n /** Read, mutate and write back, preserving on-disk style and key order. */\n mutate(filePath: string, mutate: (data: Record<string, unknown>) => void): Promise<void>\n clearCache(): void\n clearCacheEntry(filePath: string): void\n}\n\nconst formats = new Map<LocaleFileFormat, LocaleFormat>()\nconst byExtension = new Map<string, LocaleFormat>()\n\nexport function registerFormat(format: LocaleFormat): void {\n formats.set(format.id, format)\n for (const extension of format.extensions) {\n byExtension.set(extension.toLowerCase(), format)\n }\n}\n\n/**\n * The format a config's `localeFileFormat` names. Undefined resolves to JSON,\n * which is what an adapter that declares nothing has always meant.\n */\nexport function getFormat(id: LocaleFileFormat | undefined): LocaleFormat {\n const format = formats.get(id ?? 'json')\n if (!format) {\n throw new ConfigError(\n `Unknown locale file format: ${id}. Known formats: ${[...formats.keys()].join(', ')}`,\n )\n }\n return format\n}\n\n/** The format that owns a file's extension. */\nexport function formatForFile(filePath: string): LocaleFormat {\n const ext = extname(filePath).toLowerCase()\n const format = byExtension.get(ext)\n if (!format) {\n throw new FileIOError(`Unsupported locale file format: ${ext}`, filePath)\n }\n return format\n}\n\nexport function listFormats(): LocaleFormat[] {\n return [...formats.values()]\n}\n\n/**\n * Guess the format of a locale directory from the files in it — flat\n * `en.json` / `en.php` / `en.yaml` first, then a directory per locale. Returns\n * null when nothing recognizable is there, leaving the default to the caller. A\n * directory holding more than one format resolves to whichever has the most\n * files and warns, because the format that loses is invisible from then on.\n */\nexport async function detectFormatInDir(localeDir: string): Promise<LocaleFileFormat | null> {\n let entries: import('node:fs').Dirent[]\n try {\n entries = await readdir(localeDir, { withFileTypes: true })\n }\n catch {\n return null\n }\n\n // Flat files: en.json, de.json, en.yaml — or en.php, de.php for a PHP\n // project that does not use Laravel's directory-per-locale layout.\n const flat = decide(countFormats(entries.filter(e => e.isFile()).map(e => e.name)), localeDir)\n if (flat) return flat\n\n // Directory-per-locale: en/, de/ — check contents.\n const nested = new Map<LocaleFileFormat, number>()\n for (const entry of entries) {\n if (!entry.isDirectory()) continue\n const subFiles = await readdir(join(localeDir, entry.name)).catch(() => [] as string[])\n for (const [id, count] of countFormats(subFiles)) {\n nested.set(id, (nested.get(id) ?? 0) + count)\n }\n }\n return decide(nested, localeDir)\n}\n\nfunction countFormats(fileNames: string[]): Map<LocaleFileFormat, number> {\n const counts = new Map<LocaleFileFormat, number>()\n for (const name of fileNames) {\n const format = byExtension.get(extname(name).toLowerCase())\n if (!format) continue\n counts.set(format.id, (counts.get(format.id) ?? 0) + 1)\n }\n return counts\n}\n\nfunction decide(counts: Map<LocaleFileFormat, number>, localeDir: string): LocaleFileFormat | null {\n let winner: LocaleFileFormat | null = null\n let best = 0\n // Walked in registration order, so an exact tie always resolves the same way.\n for (const id of formats.keys()) {\n const count = counts.get(id) ?? 0\n if (count > best) {\n winner = id\n best = count\n }\n }\n if (!winner) return null\n\n if (counts.size > 1) {\n const seen = [...counts.entries()].map(([id, count]) => `${id} (${count})`).join(', ')\n log.warn(\n `Locale directory ${localeDir} mixes file formats: ${seen}. Reading and writing it as `\n + `'${winner}' — files in the other formats are ignored. Keep one format per locale directory.`,\n )\n }\n\n return winner\n}\n\n// Registration order is the tie-break order in `decide`: JSON first keeps a\n// mixed directory resolving the way it did before the files were counted.\nregisterFormat({\n id: 'json',\n extensions: ['.json'],\n defaultLayout: 'flat',\n flatFileFromDisk: false,\n read: readLocaleFile,\n write: (filePath, data, options) => writeLocaleFile(filePath, data, options),\n mutate: mutateLocaleFile,\n clearCache: clearFileCache,\n clearCacheEntry: clearFileCacheEntry,\n})\n\nregisterFormat({\n id: 'php-array',\n extensions: ['.php'],\n defaultLayout: 'namespaced',\n flatFileFromDisk: true,\n read: readPhpLocaleFile,\n write: (filePath, data, options) => writePhpLocaleFile(filePath, data, options),\n mutate: mutatePhpLocaleFile,\n clearCache: clearPhpFileCache,\n clearCacheEntry: clearPhpFileCacheEntry,\n})\n\n// Rails, Symfony and vue-i18n all read `.yaml`; `.yml` is the same format\n// under the extension half of them actually use.\nregisterFormat({\n id: 'yaml',\n extensions: ['.yaml', '.yml'],\n defaultLayout: 'flat',\n flatFileFromDisk: false,\n read: readYamlLocaleFile,\n write: (filePath, data, options) => writeYamlLocaleFile(filePath, data, options),\n mutate: mutateYamlLocaleFile,\n clearCache: clearYamlFileCache,\n clearCacheEntry: clearYamlFileCacheEntry,\n})\n","import type { FrameworkAdapter } from './types'\nimport { ConfigError, toErrorMessage } from '../utils/errors'\nimport { log } from '../utils/logger'\n\nconst adapters: FrameworkAdapter[] = []\n\nexport function registerAdapter(adapter: FrameworkAdapter): void {\n adapters.push(adapter)\n}\n\nexport function resetRegistry(): void {\n adapters.length = 0\n}\n\n/**\n * Names that no longer have an adapter of their own, mapped to the one that\n * resolves those projects now. Kept so a config written against a retired\n * adapter keeps validating and resolving instead of failing on an unknown\n * hint, and warned about because the replacement needs more from the config\n * than the retired adapter did.\n */\nconst RETIRED_HINTS: Record<string, { replacement: string, warning: string }> = {\n vue: {\n replacement: 'generic',\n warning: 'vue projects resolve through the generic adapter; declare localeDirs',\n },\n}\n\nfunction resolveHint(hint: string): string {\n const retired = RETIRED_HINTS[hint]\n if (!retired) return hint\n log.warn(`framework: \"${hint}\" — ${retired.warning}`)\n return retired.replacement\n}\n\n/**\n * The names of every registered adapter, in registration order. The published\n * JSON Schema advertises these as `framework` suggestions, so an adapter added\n * later shows up in editors without anyone editing a list by hand.\n */\nexport function listAdapterNames(): string[] {\n return adapters.map(a => a.name)\n}\n\nexport interface FrameworkMatch {\n adapter: FrameworkAdapter\n /** Detection score. 0 when the adapter was forced by hint rather than detected. */\n confidence: number\n /** Every adapter that scored above zero, best first — context for `init`. */\n runnersUp: Array<{ name: string; confidence: number }>\n}\n\n/**\n * Detect the framework and report how confidently. `detectFramework` returns\n * only the winner; `init` needs the score to tell a user why Nuxt was chosen\n * over generic, and a bare directory needs to be distinguishable from a\n * confident match rather than surfacing as a thrown error.\n */\nexport async function detectFrameworkMatch(\n projectDir: string,\n hint?: string,\n): Promise<FrameworkMatch | undefined> {\n if (adapters.length === 0) {\n throw new ConfigError('No framework adapters registered.')\n }\n\n if (hint) {\n // Resolved once, not inside the predicate: the predicate runs per adapter,\n // and the retirement warning is about the hint, not about the search.\n const name = resolveHint(hint)\n const match = adapters.find(a => a.name === name)\n if (!match) return undefined\n return { adapter: match, confidence: 0, runnersUp: [] }\n }\n\n const scores = await Promise.all(\n adapters.map(async (adapter) => {\n try {\n return { adapter, confidence: await adapter.detect(projectDir) }\n }\n catch (error) {\n log.warn(`Adapter '${adapter.name}' detection failed: ${toErrorMessage(error)}`)\n return { adapter, confidence: 0 }\n }\n }),\n )\n\n const ranked = scores.filter(s => s.confidence > 0).sort((a, b) => b.confidence - a.confidence)\n const [best] = ranked\n if (!best) return undefined\n\n return {\n adapter: best.adapter,\n confidence: best.confidence,\n runnersUp: ranked.slice(1).map(s => ({ name: s.adapter.name, confidence: s.confidence })),\n }\n}\n\nexport async function detectFramework(\n projectDir: string,\n hint?: string,\n): Promise<FrameworkAdapter> {\n const match = await detectFrameworkMatch(projectDir, hint)\n if (match) return match.adapter\n\n if (hint) {\n throw new ConfigError(\n `Framework hint \"${hint}\" does not match any registered adapter. `\n + `Available: ${adapters.map(a => a.name).join(', ')}`,\n )\n }\n throw new ConfigError(\n `No framework detected for ${projectDir}. `\n + `Registered adapters: ${adapters.map(a => a.name).join(', ')}. `\n + 'Declare localeDirs and defaultLocale to resolve the project through the generic adapter.',\n )\n}\n","/**\n * Directory helpers every framework shares: identifying a project directory,\n * and naming a layer after where it sits. Finding the apps in a project is a\n * framework's own business and lives with its adapter.\n */\nimport { realpathSync } from 'node:fs'\nimport { resolve, relative } from 'node:path'\n\nexport function canonicalPath(dir: string): string {\n try {\n return realpathSync(resolve(dir))\n }\n catch {\n return resolve(dir)\n }\n}\n\n/**\n * Derive a human-friendly layer name from its root directory.\n * Uses the discovery root as the reference point for naming.\n *\n * When `usedNames` is provided, disambiguates collisions by progressively\n * including parent path segments (e.g., `admin` → `apps/admin`).\n */\nexport function deriveLayerName(\n layerRootDir: string,\n discoveryRoot: string,\n usedNames?: Set<string>,\n): string {\n const rel = relative(discoveryRoot, layerRootDir)\n if (rel === '' || rel === '.') {\n return 'root'\n }\n\n const posixRel = rel.replace(/\\\\/g, '/')\n\n if (!posixRel.startsWith('..')) {\n const segments = posixRel.split('/')\n let candidate = segments.pop() ?? posixRel\n\n if (usedNames) {\n for (let i = segments.length - 1; i >= 0; i--) {\n if (!usedNames.has(candidate)) break\n candidate = `${segments[i]}/${candidate}`\n }\n }\n\n return candidate\n }\n\n const parts = layerRootDir.replace(/\\\\/g, '/').split('/')\n let candidate = parts.pop() ?? layerRootDir\n\n if (usedNames) {\n for (let i = parts.length - 1; i >= 0; i--) {\n if (!usedNames.has(candidate)) break\n candidate = `${parts[i]}/${candidate}`\n }\n }\n\n return candidate\n}\n","import type { LocaleDefinition } from './types'\nimport { log } from '../utils/logger'\n\n/**\n * Apply the optional `locales` override from `.i18n-mcp.json` on top of the\n * locales auto-discovered by a framework adapter.\n *\n * Semantics:\n * - If `projectLocales` is unset/empty → return `discovered` unchanged.\n * - Else → restrict to the configured codes, preserving the order from\n * `projectLocales` and keeping the metadata (file, language, name) from\n * the discovered entries. Configured codes with no matching discovered\n * entry get a minimal `{code, language: code}` fallback and a warning.\n */\nexport function applyLocaleOverride(\n discovered: LocaleDefinition[],\n projectLocales: string[] | undefined,\n): LocaleDefinition[] {\n if (!projectLocales || projectLocales.length === 0) {\n return discovered\n }\n\n const byCode = new Map(discovered.map(l => [l.code, l]))\n const missing: string[] = []\n\n const result = projectLocales.map((code) => {\n const found = byCode.get(code)\n if (found) return found\n missing.push(code)\n return { code, language: code }\n })\n\n if (missing.length > 0) {\n log.warn(\n `Configured locales not found in framework auto-detection: ${missing.join(', ')}. `\n + 'Translations for these codes may fail to write — make sure the locale files exist.',\n )\n }\n\n const dropped = discovered.filter(l => !projectLocales.includes(l.code))\n if (dropped.length > 0) {\n log.debug(\n `Locale override active: dropped ${dropped.length} auto-detected locale(s) `\n + `(${dropped.map(l => l.code).join(', ')})`,\n )\n }\n\n return result\n}\n","/**\n * Normalise `@nuxtjs/i18n`'s `fallbackLocale` — a string, an array, or a\n * per-locale map — into the single map shape the rest of the CLI reads.\n *\n * Shared by both paths on purpose. The Nuxt module publishes this value exactly\n * as Nuxt resolved it rather than normalising it itself: two implementations of\n * the same normalisation, in two packages that do not depend on each other, is\n * precisely the drift the module exists to remove.\n */\nexport function normalizeFallbackLocale(\n fallback: unknown,\n defaultLocale: string,\n): Record<string, string[]> {\n if (typeof fallback === 'string') {\n return { default: [fallback] }\n }\n\n if (Array.isArray(fallback)) {\n return { default: (fallback as unknown[]).map(String) }\n }\n\n if (fallback && typeof fallback === 'object') {\n const result: Record<string, string[]> = {}\n for (const [key, value] of Object.entries(fallback as Record<string, unknown>)) {\n if (Array.isArray(value)) {\n result[key] = value.map(String)\n }\n else if (typeof value === 'string') {\n result[key] = [value]\n }\n }\n return result\n }\n\n return { default: [defaultLocale] }\n}\n","import { existsSync, statSync } from 'node:fs'\nimport { readdir, readFile } from 'node:fs/promises'\nimport { resolve, relative } from 'node:path'\n\nconst NUXT_CONFIG_FILES = ['nuxt.config.ts', 'nuxt.config.js', 'nuxt.config.mjs'] as const\n\nconst SKIP_DIRS = new Set([\n 'node_modules', '.nuxt', '.output', '.git', 'dist', '.cache',\n])\n\nconst MAX_DISCOVERY_DEPTH = 4\n\nexport function findNuxtConfig(dir: string): string | null {\n for (const name of NUXT_CONFIG_FILES) {\n if (existsSync(resolve(dir, name))) {\n return name\n }\n }\n return null\n}\n\nasync function hasI18nConfig(configPath: string): Promise<boolean> {\n try {\n const content = await readFile(configPath, 'utf-8')\n return /\\bi18n\\b/.test(content)\n }\n catch {\n return false\n }\n}\n\n/**\n * Discover all Nuxt apps with i18n configuration under a root directory.\n * Scans recursively up to MAX_DISCOVERY_DEPTH levels deep,\n * skipping common non-project directories.\n *\n * Returns sorted absolute paths to directories that:\n * 1. Contain a nuxt.config.{ts,js,mjs} file\n * 2. The config file references i18n\n */\nexport async function discoverNuxtApps(rootDir: string): Promise<string[]> {\n const apps: string[] = []\n await scanForApps(rootDir, 0, apps, true)\n const root = resolve(rootDir)\n apps.sort((a, b) => relative(root, a).localeCompare(relative(root, b)))\n return apps\n}\n\nasync function scanForApps(dir: string, depth: number, results: string[], isRoot = false): Promise<void> {\n if (depth > MAX_DISCOVERY_DEPTH) return\n\n const configFile = findNuxtConfig(dir)\n if (configFile) {\n const configPath = resolve(dir, configFile)\n if (await hasI18nConfig(configPath)) {\n results.push(dir)\n }\n if (!isRoot) return\n }\n\n let entries: string[]\n try {\n entries = await readdir(dir)\n }\n catch {\n return\n }\n\n for (const entry of entries) {\n if (entry.startsWith('.') || SKIP_DIRS.has(entry)) continue\n const childDir = resolve(dir, entry)\n try {\n const stat = statSync(childDir)\n if (!stat.isDirectory()) continue\n }\n catch {\n continue\n }\n await scanForApps(childDir, depth + 1, results)\n }\n}\n","import { log } from '../../utils/logger'\n\ntype NuxtKit = typeof import('@nuxt/kit')\n\n/** Import `id` resolved against the project's node_modules rather than our own. */\nasync function importModuleFrom(id: string, rootDir: string): Promise<unknown> {\n const { createRequire } = await import('node:module')\n const require = createRequire(rootDir + '/')\n const resolved = require.resolve(id)\n return import(resolved)\n}\n\n/**\n * Load @nuxt/kit from the project's own node_modules.\n * Falls back to trying common Nuxt package names.\n */\nexport async function loadKit(rootDir: string): Promise<NuxtKit> {\n try {\n const kit = await importModuleFrom('@nuxt/kit', rootDir) as NuxtKit\n log.debug(`Loaded @nuxt/kit from project: ${rootDir}`)\n return kit\n } catch (e: unknown) {\n const message = String(e)\n if (message.includes(\"Cannot find module '@nuxt/kit'\")) {\n throw new Error(\n '@nuxt/kit is required for Nuxt projects but was not found. '\n + 'Install it with: npm install --save-dev @nuxt/kit\\n'\n + 'Laravel projects do not need @nuxt/kit — if this is a Laravel project, '\n + 'check that your .i18n-mcp.json has \"framework\": \"laravel\" or that '\n + 'your project structure is detected correctly.',\n )\n }\n throw e\n }\n}\n","import { sep } from 'node:path'\nimport type { LocaleDir } from '../../config/types'\nimport { log } from '../../utils/logger'\n\nexport interface LayerRef {\n layer: string\n layerRootDir: string\n}\n\nexport interface OwnershipResult {\n owner: string\n alias: string\n}\n\nfunction isAncestorOf(ancestorDir: string, childPath: string): boolean {\n const normalized = ancestorDir.endsWith(sep) ? ancestorDir : ancestorDir + sep\n return childPath.startsWith(normalized) || childPath === ancestorDir\n}\n\nfunction ancestorDepth(ancestorDir: string, childPath: string): number {\n if (!isAncestorOf(ancestorDir, childPath)) return -1\n return ancestorDir.split(sep).filter(Boolean).length\n}\n\nexport function resolveLayerOwnership(\n existing: LayerRef,\n incoming: LayerRef,\n localeDirPath: string,\n): OwnershipResult {\n const existingIsAncestor = isAncestorOf(existing.layerRootDir, localeDirPath)\n const incomingIsAncestor = isAncestorOf(incoming.layerRootDir, localeDirPath)\n\n if (existingIsAncestor && !incomingIsAncestor) {\n return { owner: existing.layer, alias: incoming.layer }\n }\n\n if (incomingIsAncestor && !existingIsAncestor) {\n return { owner: incoming.layer, alias: existing.layer }\n }\n\n if (existingIsAncestor && incomingIsAncestor) {\n const existingDepth = ancestorDepth(existing.layerRootDir, localeDirPath)\n const incomingDepth = ancestorDepth(incoming.layerRootDir, localeDirPath)\n if (incomingDepth > existingDepth) {\n return { owner: incoming.layer, alias: existing.layer }\n }\n return { owner: existing.layer, alias: incoming.layer }\n }\n\n return { owner: existing.layer, alias: incoming.layer }\n}\n\n/**\n * Claim a locale directory for a layer, deduplicating by real path.\n *\n * Mutates `dirs` and `claims`:\n * - First claim for `realPath`: the incoming dir is pushed and recorded as owner.\n * - Same path already claimed and the incoming layer wins ownership\n * (see `resolveLayerOwnership`): the incoming dir replaces the previous\n * owner in place, and the previous owner is re-pushed demoted to an alias.\n * - Same path already claimed and the existing layer keeps ownership: the\n * incoming dir is pushed as an alias of the owner (unless it *is* the owner).\n * - If the recorded owner cannot be found as a non-alias entry (it was itself\n * demoted to an alias by an earlier takeover on another path), the incoming\n * dir is still pushed as an alias — a claim never silently drops a dir.\n */\nexport function claimLocaleDir(\n dirs: LocaleDir[],\n claims: Map<string, LayerRef>,\n incoming: LocaleDir,\n realPath: string,\n): void {\n const existing = claims.get(realPath)\n\n if (!existing) {\n claims.set(realPath, { layer: incoming.layer, layerRootDir: incoming.layerRootDir })\n dirs.push({ ...incoming })\n return\n }\n\n const { owner, alias } = resolveLayerOwnership(\n { layer: existing.layer, layerRootDir: existing.layerRootDir },\n { layer: incoming.layer, layerRootDir: incoming.layerRootDir },\n realPath,\n )\n\n if (owner !== existing.layer) {\n const ownerIndex = dirs.findIndex(d => d.layer === existing.layer && !d.aliasOf)\n const previousOwner = ownerIndex !== -1 ? dirs[ownerIndex] : undefined\n if (previousOwner) {\n const promoted = { ...incoming }\n delete promoted.aliasOf\n dirs[ownerIndex] = promoted\n dirs.push({ ...previousOwner, aliasOf: owner })\n claims.set(realPath, { layer: incoming.layer, layerRootDir: incoming.layerRootDir })\n log.debug(`Layer '${alias}' is alias of '${owner}' (ancestor-based ownership, same path: ${incoming.path})`)\n }\n else {\n // Recorded owner is itself an alias — keep the incoming dir as an alias\n // instead of dropping it.\n dirs.push({ ...incoming, aliasOf: existing.layer })\n log.debug(`Layer '${incoming.layer}' is alias of '${existing.layer}' (owner already aliased, same path: ${incoming.path})`)\n }\n }\n else if (incoming.layer !== existing.layer) {\n dirs.push({ ...incoming, aliasOf: owner })\n log.debug(`Layer '${alias}' is alias of '${owner}' (same path: ${incoming.path})`)\n }\n}\n","import { existsSync, statSync } from 'node:fs'\nimport { readFile, realpath } from 'node:fs/promises'\nimport { resolve } from 'node:path'\nimport { z } from 'zod'\nimport type { AppInfo, I18nConfig, LocaleDefinition, LocaleDir, ProjectConfig } from '../../config/types.js'\nimport { deriveLayerName } from '../../config/paths.js'\nimport { applyLocaleOverride } from '../../config/locale-override.js'\nimport { normalizeFallbackLocale } from '../../config/fallback-locale.js'\nimport { log } from '../../utils/logger.js'\nimport { findNuxtConfig } from './discovery.js'\nimport { claimLocaleDir } from './layer-dedup.js'\n\n/** Where @the-i18n-kit/nuxt publishes what Nuxt resolved, relative to an app. */\nconst ARTIFACT_PATH = '.nuxt/i18n-kit.json'\n\nconst localeSchema = z.object({\n code: z.string().min(1),\n language: z.string(),\n file: z.string().min(1),\n name: z.string().optional(),\n})\n\nconst layerSchema = z.object({\n rootDir: z.string().min(1),\n localeDir: z.string().min(1).optional(),\n})\n\nconst artifactSchema = z.object({\n version: z.literal(1),\n generator: z.string(),\n appDir: z.string().min(1),\n defaultLocale: z.string().min(1),\n // As Nuxt resolved it, in any of the three shapes @nuxtjs/i18n accepts.\n // Normalising it here rather than in the module keeps one implementation.\n fallbackLocale: z.union([\n z.string(),\n z.array(z.string()),\n z.record(z.string(), z.union([z.string(), z.array(z.string())])),\n z.null(),\n ]),\n localeFileFormat: z.literal('json'),\n locales: z.array(localeSchema).min(1),\n layers: z.array(layerSchema).min(1),\n})\n\nexport type I18nKitArtifact = z.infer<typeof artifactSchema>\n\n/**\n * Read an app's artifact, or null when there isn't a usable one.\n *\n * Never throws: every failure here — absent, malformed, a version this CLI\n * does not know, or older than the config it claims to describe — means\n * falling back to loading the app through Nuxt, which is what happens today\n * anyway. A module that cannot be trusted must not be able to break a project\n * that worked without it.\n */\nexport async function readArtifact(appDir: string): Promise<I18nKitArtifact | null> {\n const path = resolve(appDir, ARTIFACT_PATH)\n if (!existsSync(path)) return null\n\n let parsed: unknown\n try {\n parsed = JSON.parse(await readFile(path, 'utf-8'))\n }\n catch (error) {\n log.warn(`Ignoring ${path}: ${error instanceof Error ? error.message : String(error)}`)\n return null\n }\n\n const result = artifactSchema.safeParse(parsed)\n if (!result.success) {\n const [issue] = result.error.issues\n const where = issue?.path.join('.') || '(root)'\n log.warn(`Ignoring ${path}: not a shape this CLI understands (${where}: ${issue?.message}).`)\n return null\n }\n\n // Staleness is checked after parsing so the layers can be checked too: a\n // layer's own config decides that layer's locales, and an app config that\n // has not changed says nothing about the layers it extends.\n const changed = staleAgainst(result.data, path)\n if (changed) {\n log.warn(\n `Ignoring ${path}: ${changed} has changed since it was generated. `\n + 'Run `nuxt prepare` to refresh it — falling back to loading the app.',\n )\n return null\n }\n\n log.info(`Using the layer graph published by ${result.data.generator}`)\n return result.data\n}\n\n/**\n * An artifact older than any config it describes is a lie about the current\n * project, and a quiet one. Cheaper to distrust it than to explain later why a\n * renamed locale never took effect.\n *\n * Returns the config that outdates it, for the message; undefined when the\n * artifact is current, when no config can be found, or when a stat fails —\n * unreadable timestamps are not evidence of staleness.\n */\nfunction staleAgainst(artifact: I18nKitArtifact, artifactPath: string): string | undefined {\n let artifactMtime: number\n try {\n artifactMtime = statSync(artifactPath).mtimeMs\n }\n catch {\n return undefined\n }\n\n const dirs = [artifact.appDir, ...artifact.layers.map(l => l.rootDir)]\n\n for (const dir of new Set(dirs)) {\n const configFile = findNuxtConfig(dir)\n if (!configFile) continue\n\n const configPath = resolve(dir, configFile)\n try {\n if (statSync(configPath).mtimeMs > artifactMtime) return configPath\n }\n catch {\n continue\n }\n }\n\n return undefined\n}\n\n/**\n * Turn one app's artifact into the config shape every command consumes.\n *\n * Layer *names* are derived here rather than read from the artifact: they\n * depend on the directory the CLI was pointed at, which the module cannot\n * know. Deriving them in one place is what keeps the artifact path and the\n * fallback path producing the same names for the same project.\n */\nexport async function artifactToConfig(\n artifact: I18nKitArtifact,\n appDir: string,\n discoveryRoot: string,\n projectConfig: ProjectConfig | null,\n): Promise<I18nConfig> {\n const localeDirs: LocaleDir[] = []\n const claimed = new Map<string, { layer: string, layerRootDir: string }>()\n const usedLayerNames = new Set<string>()\n\n for (const layer of artifact.layers) {\n // Named before the locale-dir check, and unconditionally: a layer without\n // translations still consumes its name, so that layers with translations\n // get the same names they would on the fallback path.\n const layerName = deriveLayerName(layer.rootDir, discoveryRoot, usedLayerNames)\n usedLayerNames.add(layerName)\n\n if (!layer.localeDir) continue\n\n const realDir = await realpath(layer.localeDir).catch(() => layer.localeDir!)\n claimLocaleDir(\n localeDirs,\n claimed,\n { path: layer.localeDir, layer: layerName, layerRootDir: layer.rootDir },\n realDir,\n )\n }\n\n const layerRootDirs = [...new Set(artifact.layers.map(l => l.rootDir))]\n if (layerRootDirs.length === 0) layerRootDirs.push(appDir)\n\n const namesForApp = new Set<string>()\n const app: AppInfo = {\n name: deriveLayerName(appDir, discoveryRoot, new Set()),\n rootDir: appDir,\n layers: artifact.layers.map(l => deriveLayerName(l.rootDir, discoveryRoot, namesForApp)),\n }\n\n const locales: LocaleDefinition[] = artifact.locales.map(l => ({\n code: l.code,\n language: l.language,\n file: l.file,\n ...(l.name === undefined ? {} : { name: l.name }),\n }))\n\n return {\n rootDir: appDir,\n defaultLocale: artifact.defaultLocale,\n fallbackLocale: normalizeFallbackLocale(artifact.fallbackLocale, artifact.defaultLocale),\n locales: applyLocaleOverride(locales, projectConfig?.locales),\n localeDirs,\n layerRootDirs,\n projectConfig: projectConfig ?? undefined,\n apps: [app],\n }\n}\n","import { realpath } from 'node:fs/promises'\nimport type { AppInfo, I18nConfig, LocaleDefinition, LocaleDir } from '../../config/types'\nimport { deriveLayerName } from '../../config/paths'\nimport { claimLocaleDir } from './layer-dedup'\n\n/**\n * Folds several Nuxt apps into one project config.\n *\n * A monorepo's apps overlap: they extend the same root layer, sometimes alias\n * each other's locale directories, and each reports the full locale table its\n * layers declare. Merging them is therefore four separate reconciliations —\n * directories claimed once by real path, locales deduplicated by code, layer\n * roots kept unique, and app→layer edges rewritten to whatever the directory\n * ended up being called. Keeping that state in one place stops the caller from\n * having to hold all four in its head at once.\n */\nexport class AppMerger {\n readonly localeDirs: LocaleDir[] = []\n readonly locales: LocaleDefinition[] = []\n readonly layerRootDirs: string[] = []\n readonly apps: AppInfo[] = []\n\n defaultLocale = 'en'\n fallbackLocale: Record<string, string[]> = { default: ['en'] }\n\n private readonly claimedPaths = new Map<string, { layer: string, layerRootDir: string }>()\n private readonly seenLocaleCodes = new Set<string>()\n private readonly usedLayerNames = new Set<string>()\n\n async add(appConfig: I18nConfig, discoveryRoot: string): Promise<void> {\n // The first app to be merged sets the project defaults. Checked against the\n // directories rather than a flag, so an app that contributed none does not\n // get to claim them.\n if (this.localeDirs.length === 0) {\n this.defaultLocale = appConfig.defaultLocale\n this.fallbackLocale = appConfig.fallbackLocale\n }\n\n const renamedLayers = await this.claimDirs(appConfig, discoveryRoot)\n this.collectLocales(appConfig)\n this.collectLayerRoots(appConfig)\n this.collectApps(appConfig, renamedLayers)\n }\n\n toConfig(discoveryRoot: string, projectConfig: I18nConfig['projectConfig'], locales: LocaleDefinition[]): I18nConfig {\n return {\n rootDir: discoveryRoot,\n defaultLocale: this.defaultLocale,\n fallbackLocale: this.fallbackLocale,\n locales,\n localeDirs: this.localeDirs,\n layerRootDirs: this.layerRootDirs,\n projectConfig,\n apps: this.apps,\n }\n }\n\n /**\n * Claim each of this app's locale directories, renaming a layer whose name is\n * already taken by a different directory. Returns the renames, because the\n * app's own layer list still refers to the old names.\n */\n private async claimDirs(appConfig: I18nConfig, discoveryRoot: string): Promise<Map<string, string>> {\n const renamed = new Map<string, string>()\n\n for (const dir of appConfig.localeDirs) {\n const realPath = await realpath(dir.path).catch(() => dir.path)\n\n // An already-claimed path keeps the name its first claimant gave it;\n // claimLocaleDir records this app as an alias of that layer.\n let claim = dir\n if (!this.claimedPaths.has(realPath)) {\n const layer = this.uniqueLayerName(dir, discoveryRoot)\n if (layer !== dir.layer) renamed.set(dir.layer, layer)\n this.usedLayerNames.add(layer)\n claim = { ...dir, layer }\n }\n\n claimLocaleDir(this.localeDirs, this.claimedPaths, claim, realPath)\n }\n\n return renamed\n }\n\n private uniqueLayerName(dir: LocaleDir, discoveryRoot: string): string {\n if (!this.usedLayerNames.has(dir.layer)) return dir.layer\n return deriveLayerName(dir.layerRootDir, discoveryRoot, this.usedLayerNames)\n }\n\n private collectLocales(appConfig: I18nConfig): void {\n for (const locale of appConfig.locales) {\n if (this.seenLocaleCodes.has(locale.code)) continue\n this.seenLocaleCodes.add(locale.code)\n this.locales.push(locale)\n }\n }\n\n private collectLayerRoots(appConfig: I18nConfig): void {\n for (const rootDir of appConfig.layerRootDirs) {\n if (!this.layerRootDirs.includes(rootDir)) this.layerRootDirs.push(rootDir)\n }\n }\n\n private collectApps(appConfig: I18nConfig, renamedLayers: Map<string, string>): void {\n for (const app of appConfig.apps) {\n this.apps.push({ ...app, layers: app.layers.map(name => renamedLayers.get(name) ?? name) })\n }\n }\n}\n","import { existsSync } from 'node:fs'\nimport { readdir, readFile, realpath } from 'node:fs/promises'\nimport { resolve, relative } from 'node:path'\nimport type { FrameworkAdapter, LocaleFileFormat } from '../types'\nimport type { I18nConfig, LocaleDefinition, LocaleDir, AppInfo, ProjectConfig } from '../../config/types'\nimport { deriveLayerName } from '../../config/paths'\nimport { applyLocaleOverride } from '../../config/locale-override'\nimport { normalizeFallbackLocale } from '../../config/fallback-locale'\nimport { log } from '../../utils/logger'\nimport { ConfigError, toErrorMessage } from '../../utils/errors'\nimport { findNuxtConfig, discoverNuxtApps } from './discovery'\nimport { loadKit } from './kit-loader'\nimport { artifactToConfig, readArtifact } from './artifact'\nimport { claimLocaleDir } from './layer-dedup'\nimport { AppMerger } from './merge-apps'\n\nexport class NuxtAdapter implements FrameworkAdapter {\n readonly name = 'nuxt'\n readonly label = 'Nuxt'\n readonly localeFileFormat: LocaleFileFormat = 'json'\n\n async detect(projectDir: string): Promise<number> {\n const configFile = findNuxtConfig(projectDir)\n if (configFile) {\n try {\n const content = await readFile(resolve(projectDir, configFile), 'utf-8')\n if (/\\bi18n\\b/.test(content)) return 2\n }\n catch {\n // Fall through to child app scan\n }\n\n // Root config exists but has no i18n — check child apps\n const appDirs = await discoverNuxtApps(projectDir)\n return appDirs.length > 0 ? 2 : 1\n }\n\n const appDirs = await discoverNuxtApps(projectDir)\n return appDirs.length > 0 ? 2 : 0\n }\n\n async resolve(projectDir: string, projectConfig: ProjectConfig | null): Promise<I18nConfig> {\n const appDirs = await discoverNuxtApps(projectDir)\n\n if (findNuxtConfig(projectDir) && !appDirs.includes(projectDir)) {\n appDirs.unshift(projectDir)\n }\n\n if (appDirs.length === 0) {\n throw new ConfigError(\n `No Nuxt apps with i18n configuration found under ${projectDir}. `\n + 'Make sure your Nuxt apps have a nuxt.config.ts with i18n configured.',\n )\n }\n\n const [soleAppDir] = appDirs\n if (appDirs.length === 1 && soleAppDir !== undefined) {\n const config = await loadApp(soleAppDir, projectDir, projectConfig)\n if (soleAppDir !== projectDir) {\n config.rootDir = projectDir\n const rootApp = config.apps[0]\n if (rootApp) {\n rootApp.rootDir = projectDir\n }\n }\n log.info(`Detected ${config.locales.length} locales, ${config.localeDirs.length} locale directories`)\n return config\n }\n\n log.info(`Discovered ${appDirs.length} Nuxt app(s) with i18n: ${appDirs.map(d => relative(projectDir, d) || '.').join(', ')}`)\n const config = await loadAndMergeApps(appDirs, projectDir, projectConfig)\n log.info(`Detected ${config.locales.length} locales, ${config.localeDirs.length} locale directories from ${appDirs.length} app(s)`)\n return config\n }\n}\n\n/**\n * One app's config, preferring what @the-i18n-kit/nuxt published from inside\n * the build over reconstructing it from outside. The artifact is additive: any\n * reason not to trust it falls through to loading the app exactly as before,\n * so a project without the module — or with a stale one — behaves as it always\n * has.\n */\nasync function loadApp(\n appDir: string,\n discoveryRoot: string,\n projectConfig: ProjectConfig | null,\n): Promise<I18nConfig> {\n const artifact = await readArtifact(appDir)\n if (!artifact) return loadSingleApp(appDir, discoveryRoot, projectConfig)\n\n const config = await artifactToConfig(artifact, appDir, discoveryRoot, projectConfig)\n\n // An artifact describing no locale directory leaves nothing to read, which\n // the fallback path reports as a ConfigError naming what is missing. Silently\n // returning an empty config instead would make installing the module turn a\n // clear error into no output at all.\n if (config.localeDirs.length === 0) {\n log.warn(`The artifact for ${appDir} describes no locale directories — loading the app instead.`)\n return loadSingleApp(appDir, discoveryRoot, projectConfig)\n }\n\n return config\n}\n\nasync function loadSingleApp(\n appDir: string,\n discoveryRoot: string,\n projectConfig: ProjectConfig | null,\n): Promise<I18nConfig> {\n const kit = await loadKit(appDir)\n\n let nuxt: Awaited<ReturnType<typeof kit.loadNuxt>>\n\n try {\n nuxt = await kit.loadNuxt({\n cwd: appDir,\n dotenv: { cwd: appDir },\n overrides: {\n logLevel: 'silent' as const,\n vite: { clearScreen: false },\n },\n })\n }\n catch (_error) {\n log.warn(`Initial loadNuxt failed for ${appDir}, retrying with ready:false...`)\n try {\n nuxt = await kit.loadNuxt({\n cwd: appDir,\n dotenv: { cwd: appDir },\n ready: false,\n overrides: {\n logLevel: 'silent' as const,\n vite: { clearScreen: false },\n },\n })\n }\n catch (retryError) {\n throw new ConfigError(\n `Failed to load Nuxt config from ${appDir}: ${retryError instanceof Error ? retryError.message : String(retryError)}`,\n )\n }\n }\n\n try {\n return await extractI18nConfig(\n nuxt as unknown as { options: Record<string, unknown> },\n appDir,\n discoveryRoot,\n projectConfig,\n )\n }\n finally {\n await nuxt.close()\n }\n}\n\nasync function loadAndMergeApps(\n appDirs: string[],\n discoveryRoot: string,\n projectConfig: ProjectConfig | null,\n): Promise<I18nConfig> {\n const merger = new AppMerger()\n\n for (const appDir of appDirs) {\n log.info(`Loading Nuxt app: ${relative(discoveryRoot, appDir) || '.'}`)\n\n let appConfig: I18nConfig\n try {\n appConfig = await loadApp(appDir, discoveryRoot, projectConfig)\n }\n catch (error) {\n // One unloadable app must not take the others with it: a monorepo where\n // a single app fails to build still has translations worth managing.\n log.warn(`Failed to load app at ${appDir}: ${toErrorMessage(error)}`)\n continue\n }\n\n await merger.add(appConfig, discoveryRoot)\n }\n\n if (merger.localeDirs.length === 0) {\n throw new ConfigError(\n `No locale directories found in any Nuxt app under ${discoveryRoot}. `\n + 'Make sure your Nuxt apps have i18n/locales/ directories with JSON files.',\n )\n }\n\n return merger.toConfig(\n discoveryRoot,\n projectConfig ?? undefined,\n applyLocaleOverride(merger.locales, projectConfig?.locales),\n )\n}\n\nasync function extractI18nConfig(\n nuxt: { options: Record<string, unknown> },\n appDir: string,\n discoveryRoot: string,\n projectConfig: ProjectConfig | null,\n): Promise<I18nConfig> {\n const nuxtOptions = nuxt.options as Record<string, unknown>\n const i18nOptions = nuxtOptions.i18n as Record<string, unknown> | undefined\n const layers = (nuxtOptions._layers ?? []) as Array<{\n config: {\n rootDir: string\n i18n?: Record<string, unknown>\n }\n }>\n\n if (!i18nOptions) {\n throw new ConfigError(\n `No i18n configuration found in nuxt.config at ${appDir}. Make sure @nuxtjs/i18n is configured.`,\n )\n }\n\n const defaultLocale = (i18nOptions.defaultLocale as string) ?? 'en'\n log.debug(`Default locale: ${defaultLocale}`)\n\n const rawLocales = (i18nOptions.locales ?? []) as Array<Record<string, unknown>>\n const locales: LocaleDefinition[] = rawLocales\n .filter(l => typeof l === 'object' && l !== null)\n .map(l => ({\n code: String(l.code ?? ''),\n language: String(l.language ?? l.iso ?? ''),\n file: String(l.file ?? ''),\n name: l.name ? String(l.name) : undefined,\n }))\n .filter(l => l.code && l.file)\n\n if (locales.length === 0) {\n throw new ConfigError(\n 'No locales found in i18n configuration. Make sure locales are defined with code and file properties.',\n )\n }\n\n const fallbackLocale = normalizeFallbackLocale(i18nOptions.fallbackLocale, defaultLocale)\n const localeDirs = await discoverLocaleDirs(layers, i18nOptions, discoveryRoot)\n\n const layerRootDirs = [...new Set(layers.map(l => l.config.rootDir))]\n if (layerRootDirs.length === 0) {\n layerRootDirs.push(appDir)\n }\n\n const usedLayerNamesForApp = new Set<string>()\n const appLayerNames = layers.map(l => deriveLayerName(l.config.rootDir, discoveryRoot, usedLayerNamesForApp))\n const appName = deriveLayerName(appDir, discoveryRoot, new Set())\n const appInfo: AppInfo = { name: appName, rootDir: appDir, layers: appLayerNames }\n\n return {\n rootDir: appDir,\n defaultLocale,\n fallbackLocale,\n locales: applyLocaleOverride(locales, projectConfig?.locales),\n localeDirs,\n layerRootDirs,\n projectConfig: projectConfig ?? undefined,\n apps: [appInfo],\n }\n}\n\nasync function discoverLocaleDirs(\n layers: Array<{ config: { rootDir: string; i18n?: Record<string, unknown> } }>,\n i18nOptions: Record<string, unknown>,\n discoveryRoot: string,\n): Promise<LocaleDir[]> {\n const dirs: LocaleDir[] = []\n const resolvedPaths = new Map<string, { layer: string, layerRootDir: string }>()\n const usedLayerNames = new Set<string>()\n\n for (const layer of layers) {\n const layerRootDir = layer.config.rootDir\n const layerName = deriveLayerName(layerRootDir, discoveryRoot, usedLayerNames)\n usedLayerNames.add(layerName)\n const layerI18n = layer.config.i18n ?? i18nOptions\n\n const langDir = (layerI18n.langDir as string) ?? 'locales'\n const restructureDir = (layerI18n.restructureDir as string) ?? 'i18n'\n const resolvedDir = resolve(layerRootDir, restructureDir, langDir)\n\n if (!existsSync(resolvedDir)) {\n log.debug(`Locale dir not found for layer '${layerName}': ${resolvedDir}`)\n continue\n }\n\n const realDir = await realpath(resolvedDir).catch(() => resolvedDir)\n\n if (!resolvedPaths.has(realDir)) {\n const files = await readdir(resolvedDir)\n const jsonFiles = files.filter(f => f.endsWith('.json'))\n if (jsonFiles.length === 0) {\n log.debug(`No JSON files in locale dir for layer '${layerName}': ${resolvedDir}`)\n continue\n }\n log.debug(`Found locale dir for layer '${layerName}': ${resolvedDir} (${jsonFiles.length} files)`)\n }\n\n claimLocaleDir(dirs, resolvedPaths, { path: resolvedDir, layer: layerName, layerRootDir }, realDir)\n }\n\n if (dirs.length === 0) {\n throw new ConfigError(\n 'No locale directories found. Make sure your Nuxt layers have i18n/locales/ directories with JSON files.',\n )\n }\n\n return dirs\n}\n","import { existsSync, readdirSync } from 'node:fs'\nimport { readdir, readFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport type { FrameworkAdapter, LocaleFileFormat } from '../types'\nimport type { I18nConfig, LocaleDefinition, LocaleDir, ProjectConfig } from '../../config/types'\nimport { applyLocaleOverride } from '../../config/locale-override'\nimport { log } from '../../utils/logger'\nimport { ConfigError } from '../../utils/errors'\n\nexport class LaravelAdapter implements FrameworkAdapter {\n readonly name = 'laravel'\n readonly label = 'Laravel'\n readonly localeFileFormat: LocaleFileFormat = 'php-array'\n\n async detect(projectDir: string): Promise<number> {\n let score = 0\n\n if (existsSync(join(projectDir, 'artisan'))) {\n score += 2\n }\n\n try {\n const raw = await readFile(join(projectDir, 'composer.json'), 'utf-8')\n const composer = JSON.parse(raw) as Record<string, unknown>\n const require = composer.require as Record<string, unknown> | undefined\n if (require && 'laravel/framework' in require) {\n score += 2\n }\n }\n catch {\n // composer.json missing or malformed — skip\n }\n\n // Weak signal: lang/ with PHP subdirectories or JSON files\n const langDir = findLangDir(projectDir)\n if (langDir) {\n const hasLocaleFiles = await hasLocaleContent(langDir)\n if (hasLocaleFiles) score += 1\n }\n\n return score\n }\n\n async resolve(projectDir: string, projectConfig: ProjectConfig | null): Promise<I18nConfig> {\n const langDir = findLangDir(projectDir)\n if (!langDir) {\n throw new ConfigError(\n `No lang/ or resources/lang/ directory found in ${projectDir}. `\n + 'Make sure your Laravel project has a locale directory.',\n )\n }\n\n const format = resolveFormat(langDir, projectConfig?.localeFileFormat)\n\n const localeCodes = await discoverLocaleCodes(langDir, format)\n if (localeCodes.length === 0) {\n throw new ConfigError(\n getFormatError(langDir, format),\n )\n }\n\n const { defaultLocale, fallbackLocale, configLocales } = await extractLocaleConfig(projectDir)\n\n const allCodes = mergeLocaleCodes(localeCodes, configLocales)\n\n const locales: LocaleDefinition[] = applyLocaleOverride(\n allCodes.map(code => ({\n code,\n language: code,\n ...(format === 'json' ? { file: `${code}.json` } : {}),\n })),\n projectConfig?.locales,\n )\n\n const localeDirs: LocaleDir[] = [{\n path: langDir,\n layer: 'root',\n layerRootDir: projectDir,\n }]\n\n log.info(\n `Discovered ${locales.length} locale(s) in ${langDir} (${format}): `\n + `${allCodes.join(', ')}`,\n )\n\n return {\n rootDir: projectDir,\n defaultLocale,\n fallbackLocale,\n locales,\n localeDirs,\n layerRootDirs: [projectDir],\n projectConfig: projectConfig ?? undefined,\n localeFileFormat: format,\n apps: [{ name: 'root', rootDir: projectDir, layers: ['root'] }],\n }\n }\n}\n\n// ─── Format detection ───────────────────────────────────────────\n\nfunction resolveFormat(\n langDir: string,\n override?: LocaleFileFormat,\n): LocaleFileFormat {\n if (override) return override\n\n const hasJson = existsSync(join(langDir, 'en.json'))\n || existsSync(join(langDir, 'de.json'))\n || existsSync(join(langDir, 'fr.json'))\n const hasPhp = hasPhpSubdirsSync(langDir)\n\n // When both exist, prefer php-array (backward compatible)\n if (hasPhp) return 'php-array'\n if (hasJson) return 'json'\n\n return 'php-array' // default\n}\n\nfunction hasPhpSubdirsSync(langDir: string): boolean {\n try {\n const entries = readdirSync(langDir, { withFileTypes: true })\n for (const entry of entries) {\n if (!entry.isDirectory() || entry.name === 'vendor') continue\n const subEntries = readdirSync(join(langDir, entry.name))\n if (subEntries.some(f => f.endsWith('.php'))) return true\n }\n }\n catch { /* can't read */ }\n return false\n}\n\nfunction getFormatError(langDir: string, format: LocaleFileFormat): string {\n if (format === 'json') {\n return `No JSON locale files found in ${langDir}. Expected files like lang/en.json, lang/de.json.`\n }\n return `No locale subdirectories found in ${langDir}. Expected directories like lang/en/, lang/de/.`\n}\n\n// ─── Locale discovery ───────────────────────────────────────────\n\nasync function hasLocaleContent(langDir: string): Promise<boolean> {\n // Check for JSON files (flat layout)\n const entries = await readdir(langDir).catch(() => [] as string[])\n if (entries.some(f => f.endsWith('.json'))) return true\n\n // Check for PHP subdirectories (namespaced layout)\n return hasPhpContent(langDir)\n}\n\nasync function discoverLocaleCodes(\n langDir: string,\n format: LocaleFileFormat,\n): Promise<string[]> {\n if (format === 'json') {\n return discoverJsonLocales(langDir)\n }\n return findLocaleSubdirs(langDir)\n}\n\nasync function discoverJsonLocales(langDir: string): Promise<string[]> {\n const entries = await readdir(langDir).catch(() => [] as string[])\n return entries\n .filter(f => f.endsWith('.json'))\n .map(f => f.replace(/\\.json$/, ''))\n .sort()\n}\n\nasync function hasPhpContent(langDir: string): Promise<boolean> {\n const subdirs = await findLocaleSubdirs(langDir)\n return subdirs.length > 0\n}\n\n/**\n * Laravel 9+ uses root-level `lang/`, older versions use `resources/lang/`.\n */\nfunction findLangDir(projectDir: string): string | null {\n const candidates = [\n join(projectDir, 'lang'),\n join(projectDir, 'resources', 'lang'),\n ]\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return candidate\n }\n }\n return null\n}\n\nasync function findLocaleSubdirs(langDir: string): Promise<string[]> {\n let entries: import('node:fs').Dirent[]\n try {\n entries = await readdir(langDir, { withFileTypes: true })\n }\n catch {\n return []\n }\n\n const locales: string[] = []\n for (const entry of entries) {\n if (!entry.isDirectory() || entry.name === 'vendor') continue\n const files = await readdir(join(langDir, entry.name)).catch(() => [] as string[])\n if (files.some(f => f.endsWith('.php'))) {\n locales.push(entry.name)\n }\n }\n\n return locales.sort()\n}\n\n// ─── Config parsing ─────────────────────────────────────────────\n\n/**\n * Extract default and fallback locale from config/app.php.\n */\nasync function extractLocaleConfig(projectDir: string): Promise<{\n defaultLocale: string\n fallbackLocale: Record<string, string[]>\n configLocales: string[]\n}> {\n const configPath = join(projectDir, 'config', 'app.php')\n\n let content: string\n try {\n content = await readFile(configPath, 'utf-8')\n }\n catch {\n log.debug('No config/app.php found, using defaults')\n return {\n defaultLocale: 'en',\n fallbackLocale: { default: ['en'] },\n configLocales: [],\n }\n }\n\n const defaultLocale = extractPhpConfigValue(content, 'locale') ?? 'en'\n const fallbackValue = extractPhpConfigValue(content, 'fallback_locale') ?? defaultLocale\n const configLocales = extractPhpArrayValue(content, 'locales')\n\n log.debug(`Extracted locale config: locale=${defaultLocale}, fallback=${fallbackValue}, config locales=${configLocales.length}`)\n\n return {\n defaultLocale,\n fallbackLocale: { default: [fallbackValue] },\n configLocales,\n }\n}\n\nfunction extractPhpConfigValue(content: string, key: string): string | null {\n const envPattern = new RegExp(\n `['\"]${key}['\"]\\\\s*=>\\\\s*env\\\\s*\\\\(\\\\s*['\"][^'\"]*['\"]\\\\s*,\\\\s*['\"]([^'\"]+)['\"]\\\\s*\\\\)`,\n )\n const envMatch = content.match(envPattern)\n if (envMatch) {\n return envMatch[1] ?? null\n }\n\n const directPattern = new RegExp(\n `['\"]${key}['\"]\\\\s*=>\\\\s*['\"]([^'\"]+)['\"]`,\n )\n const directMatch = content.match(directPattern)\n if (directMatch) {\n return directMatch[1] ?? null\n }\n\n return null\n}\n\nfunction extractPhpArrayValue(content: string, key: string): string[] {\n const pattern = new RegExp(\n `['\"]${key}['\"]\\\\s*=>\\\\s*\\\\[([^\\\\]]*)]`,\n )\n const match = content.match(pattern)\n const arrayBody = match?.[1]\n if (arrayBody === undefined) return []\n\n const itemPattern = /['\"]([^'\"]+)['\"]/g\n const items: string[] = []\n let itemMatch: RegExpExecArray | null\n while ((itemMatch = itemPattern.exec(arrayBody)) !== null) {\n const item = itemMatch[1]\n if (item) items.push(item)\n }\n return items\n}\n\nfunction mergeLocaleCodes(filesystemCodes: string[], configCodes: string[]): string[] {\n const seen = new Set(filesystemCodes)\n const merged = [...filesystemCodes]\n for (const code of configCodes) {\n if (!seen.has(code)) {\n seen.add(code)\n merged.push(code)\n }\n }\n return merged.sort()\n}\n","import { readdir } from 'node:fs/promises'\nimport { join, resolve } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport type { FrameworkAdapter, LocaleFileFormat } from '../types'\nimport type { I18nConfig, LocaleDefinition, LocaleDir, ProjectConfig } from '../../config/types'\nimport { loadProjectConfig } from '../../config/project-config'\nimport { detectFormatInDir, getFormat } from '../../io/formats'\nimport { log } from '../../utils/logger'\nimport { ConfigError } from '../../utils/errors'\n\n/**\n * Where a project that declares no `localeDirs` plausibly keeps its locale\n * files, probed in order. Deliberately short and framework-neutral: it holds\n * the layouts a Vue, Svelte or plain-bundler project ends up with by\n * convention, and none that belong to an adapter of their own (`lang/` is\n * Laravel's, `messages/` and `public/locales` are React's).\n *\n * Ordered the way `init` probes the same layouts, so that a project with two\n * of them resolves to the directory init writes down rather than to a\n * different one.\n */\nconst COMMON_LOCALE_DIRS = [\n 'locales',\n 'src/locales',\n 'i18n/locales',\n 'src/i18n/locales',\n 'src/i18n',\n]\n\n/** A declaration beats every other adapter's signals. */\nconst DECLARED = 10\n\n/**\n * A probed directory beats nothing: every framework adapter scores at least\n * this much on a project it recognizes, so discovery only decides projects no\n * adapter claims.\n */\nconst DISCOVERED = 1\n\nexport class GenericAdapter implements FrameworkAdapter {\n readonly name = 'generic'\n readonly label = 'Generic'\n readonly localeFileFormat: LocaleFileFormat = 'json'\n\n // No memo of its own: the adapter is registered once for the life of the\n // process, so anything remembered here would outlive a cache clear and keep\n // reporting a config the user has already edited. Detection loads it because\n // it runs before there is anything to hand down; loading it is two file\n // reads.\n async detect(projectDir: string): Promise<number> {\n const config = await loadProjectConfig(projectDir)\n if (config?.localeDirs && config.localeDirs.length > 0 && config.defaultLocale) {\n return DECLARED\n }\n\n const probed = await findLocaleDir(projectDir)\n return probed ? DISCOVERED : 0\n }\n\n async resolve(projectDir: string, projectConfig: ProjectConfig | null): Promise<I18nConfig> {\n const localeDirs = await resolveLocaleDirs(projectDir, projectConfig)\n\n for (const dir of localeDirs) {\n if (!existsSync(dir.path)) {\n throw new ConfigError(`Locale directory does not exist: ${dir.path}`)\n }\n }\n\n // Non-empty by resolveLocaleDirs, which throws rather than returning none.\n const detectedFormat = await detectFormatInDir(localeDirs[0]!.path) ?? 'json'\n const discoveredLocales = projectConfig?.locales ?? await discoverLocales(localeDirs, detectedFormat)\n\n const [firstLocale] = discoveredLocales\n if (firstLocale === undefined) {\n throw new ConfigError(\n `No locale files found in ${localeDirs.map(d => d.path).join(', ')}`,\n )\n }\n\n // Declared beats discovered. Falling through to the first locale is\n // alphabetical order dressed up as a decision, so it is the last resort.\n const defaultLocale = projectConfig?.defaultLocale ?? firstLocale\n\n const locales: LocaleDefinition[] = await Promise.all(discoveredLocales.map(async code => ({\n code,\n language: code,\n // `file` names the flat file to read and write. A namespaced PHP layout\n // (Laravel's lang/<locale>/<namespace>.php) has no single file, and\n // resolveLocaleEntries discovers those from disk instead.\n ...(await flatFileFor(localeDirs, code, detectedFormat)),\n })))\n\n log.info(\n `Generic adapter: ${locales.length} locale(s), format=${detectedFormat}, `\n + `dirs=${localeDirs.map(d => d.layer).join(', ')}`,\n )\n\n return {\n rootDir: projectDir,\n defaultLocale,\n fallbackLocale: { default: [defaultLocale] },\n locales,\n localeDirs,\n layerRootDirs: [projectDir],\n ...(projectConfig ? { projectConfig } : {}),\n localeFileFormat: detectedFormat,\n apps: [{ name: 'default', rootDir: projectDir, layers: localeDirs.map(d => d.layer) }],\n }\n }\n}\n\n/**\n * The directories to read, declared first: a project that writes down where\n * its locale files are has settled the question, and probing is only for the\n * one that has not.\n */\nasync function resolveLocaleDirs(projectDir: string, projectConfig: ProjectConfig | null): Promise<LocaleDir[]> {\n const declared = projectConfig?.localeDirs ?? []\n if (declared.length > 0) {\n return declared.map(entry => (typeof entry === 'string'\n ? { path: resolve(projectDir, entry), layer: 'default', layerRootDir: projectDir }\n : { path: resolve(projectDir, entry.path), layer: entry.layer, layerRootDir: projectDir }))\n }\n\n const probed = await findLocaleDir(projectDir)\n if (!probed) {\n throw new ConfigError(\n 'GenericAdapter requires both \"localeDirs\" and \"defaultLocale\" in .i18n-mcp.json '\n + `when the locale files are not in a conventional directory. Looked in ${projectDir} for: `\n + `${COMMON_LOCALE_DIRS.join(', ')}.`,\n )\n }\n\n // One probed directory, one layer. Several directories are a layout only the\n // project can describe, so `localeDirs` names them and their layers.\n return [{ path: probed, layer: 'default', layerRootDir: projectDir }]\n}\n\n/**\n * The first conventional directory that holds locales, by the same rule that\n * resolves one. Judging a candidate on its contents rather than its existence\n * is what keeps an empty `src/i18n` beside a populated `locales` from claiming\n * a project and then resolving to nothing.\n *\n * Runs on every project the CLI is pointed at, including ones this adapter\n * will lose, so it reads directory entries and nothing else — no project code.\n */\nasync function findLocaleDir(projectDir: string): Promise<string | null> {\n for (const candidate of COMMON_LOCALE_DIRS) {\n const path = join(projectDir, candidate)\n if (!existsSync(path)) continue\n\n const format = await detectFormatInDir(path)\n if (!format) continue\n\n const dir: LocaleDir = { path, layer: 'default', layerRootDir: projectDir }\n if ((await discoverLocales([dir], format)).length > 0) return path\n }\n return null\n}\n\n/**\n * The flat file for a locale, when there is one. Absent for a namespaced\n * layout, where each namespace is its own file and no single name applies.\n */\nasync function flatFileFor(\n localeDirs: Array<{ path: string }>,\n code: string,\n format: LocaleFileFormat,\n): Promise<{ file?: string }> {\n for (const ext of getFormat(format).extensions) {\n for (const dir of localeDirs) {\n if (existsSync(join(dir.path, `${code}${ext}`))) return { file: `${code}${ext}` }\n }\n }\n return {}\n}\n\nconst NON_LOCALE_NAMES = new Set([\n 'index', 'readme', 'config', 'vendor', 'node_modules', '.git', '.DS_Store',\n])\n\nasync function discoverLocales(localeDirs: LocaleDir[], format: LocaleFileFormat): Promise<string[]> {\n const codes = new Set<string>()\n\n for (const dir of localeDirs) {\n let entries: import('node:fs').Dirent[]\n try {\n entries = await readdir(dir.path, { withFileTypes: true })\n }\n catch {\n continue\n }\n\n const extensions = getFormat(format).extensions\n\n for (const entry of entries) {\n if (entry.name.startsWith('.')) continue\n\n const flatExt = extensions.find(ext => entry.name.toLowerCase().endsWith(ext))\n if (entry.isFile() && flatExt) {\n const code = entry.name.slice(0, -flatExt.length)\n if (!NON_LOCALE_NAMES.has(code.toLowerCase())) {\n codes.add(code)\n }\n }\n else if (entry.isDirectory() && !NON_LOCALE_NAMES.has(entry.name.toLowerCase())) {\n const subFiles = await readdir(join(dir.path, entry.name)).catch(() => [] as string[])\n if (subFiles.some(f => extensions.some(ext => f.toLowerCase().endsWith(ext)))) {\n codes.add(entry.name)\n }\n }\n }\n }\n\n return [...codes].sort()\n}\n","/**\n * Executing config files that belong to *other* tools.\n *\n * Where a project already declares its locales authoritatively — next-intl's\n * `defineRouting`, next-translate's `i18n.js`, `next.config`'s `i18n` block —\n * reading it beats guessing from directory order. The only reason the adapters\n * ever guessed is that the CLI could not run TypeScript.\n *\n * The rule for everything in here: **never load-bearing**. A real\n * `next.config.js` is wrapped in `withNextIntl(...)` or `withSentryConfig(...)`\n * and throws without the right env or plugins installed. A file we cannot run\n * means falling back to the heuristics that were the only behaviour until now,\n * with a warning — never a failed command. It is the rule the Nuxt adapter's\n * artifact reader already follows, for the same reason.\n */\nimport { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { toErrorMessage } from '../../utils/errors.js'\nimport { log } from '../../utils/logger.js'\n\n/**\n * Run one config file and hand back its exports, or null if anything at all\n * went wrong. Callers treat null as \"no information\", not as an error.\n */\nexport async function executeConfig(\n path: string,\n options: { alias?: Record<string, string> } = {},\n): Promise<Record<string, unknown> | null> {\n try {\n const { createJiti } = await import('jiti')\n const jiti = createJiti(import.meta.url, {\n interopDefault: false,\n ...(options.alias ? { alias: options.alias } : {}),\n })\n const module = await jiti.import(path)\n return module && typeof module === 'object' ? module as Record<string, unknown> : null\n }\n catch (error) {\n log.warn(\n `Could not read ${path}: ${toErrorMessage(error)}. `\n + 'Falling back to directory detection — declare the value in i18n-kit.config.ts to be sure of it.',\n )\n return null\n }\n}\n\n/**\n * The first of `candidates` that exists under `projectDir`, as an absolute\n * path.\n *\n * Absolute, not merely joined: `--projectDir playground/react` is a relative\n * path, and a relative path handed to jiti is read as a bare module specifier\n * and resolved against `node_modules`, where it is never found.\n */\nexport function firstExisting(projectDir: string, candidates: readonly string[]): string | null {\n for (const candidate of candidates) {\n const path = resolve(projectDir, candidate)\n if (existsSync(path)) return path\n }\n return null\n}\n\n/**\n * Locate one of the stub modules in `./stubs/`, as a path jiti can be aliased\n * to. Returns null when it cannot be found, which leaves normal resolution in\n * place.\n *\n * A stub has to survive the build as a *file* — it is referred to by path and\n * never imported, so it is declared as its own tsdown entry rather than\n * bundled. That gives it two possible homes, and this resolves against the\n * location of this module, which sits beside `stubs/` in the source tree and\n * at the root of `dist/` in the bundle.\n */\nexport function resolveStub(name: string): string | null {\n const candidates = [`./stubs/${name}.ts`, `./config/framework/stubs/${name}.js`]\n\n for (const candidate of candidates) {\n const path = fileURLToPath(new URL(candidate, import.meta.url))\n if (existsSync(path)) return path\n }\n return null\n}\n\n/** A module's default export, or the module itself for a CJS `module.exports`. */\nexport function defaultExport(module: Record<string, unknown>): unknown {\n return 'default' in module ? module.default : module\n}\n\n/** Narrow an unknown to a plain object, the shape every reader here digs into. */\nexport function asObject(value: unknown): Record<string, unknown> | null {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n ? value as Record<string, unknown>\n : null\n}\n\n/** A non-empty string, or undefined — config values are not to be trusted. */\nexport function asString(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined\n}\n\n/** An array of non-empty strings, or undefined. */\nexport function asStringArray(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) return undefined\n const strings = value.filter((v): v is string => typeof v === 'string' && v.length > 0)\n return strings.length > 0 ? strings : undefined\n}\n","/**\n * Reading what a Next.js project already says about its locales.\n *\n * Three setups declare it authoritatively, and the adapter used to read none\n * of them — it took the alphabetically first file in `messages/` and called\n * that the default locale, so `{de,en,fr}.json` made German the source of\n * truth for an English project (#296).\n */\nimport { createRequire } from 'node:module'\nimport { asObject, asString, asStringArray, defaultExport, executeConfig, firstExisting, resolveStub } from './execute.js'\nimport { toErrorMessage } from '../../utils/errors.js'\nimport { log } from '../../utils/logger.js'\n\n/** next-intl: `defineRouting({ locales, defaultLocale })`, usually re-exported as `routing`. */\nconst ROUTING_FILES = [\n 'src/i18n/routing.ts',\n 'src/i18n/routing.js',\n 'i18n/routing.ts',\n 'i18n/routing.js',\n]\n\n/** next-translate: a top-level `i18n.js` consumed by `nextTranslate(...)`. */\nconst NEXT_TRANSLATE_FILES = [\n 'i18n.js',\n 'i18n.ts',\n 'i18n.mjs',\n]\n\n/** Pages Router: `i18n: { locales, defaultLocale }` in the Next config itself. */\nconst NEXT_CONFIG_FILES = [\n 'next.config.ts',\n 'next.config.js',\n 'next.config.mjs',\n]\n\nexport interface NextI18n {\n defaultLocale?: string\n locales?: string[]\n /** Which file this came from, for the message that explains the choice. */\n source: string\n}\n\n/**\n * The first source that yields something, in order of how specifically it is\n * about i18n: a routing file exists only to declare locales, whereas\n * `next.config` is mostly about everything else and the likeliest to throw.\n *\n * Returns null when no source could be read — every failure is a warning and a\n * fallback to directory detection, never an error.\n */\nexport async function readNextI18n(projectDir: string): Promise<NextI18n | null> {\n const readers = [readRouting, readNextTranslate, readNextConfig]\n\n for (const reader of readers) {\n const found = await reader(projectDir)\n if (found?.defaultLocale || found?.locales) {\n log.info(`Read i18n from ${found.source}: defaultLocale=${found.defaultLocale ?? '(none)'}`)\n return found\n }\n }\n\n return null\n}\n\n/**\n * next-intl. `defineRouting` returns the object it was handed, so the exported\n * routing object carries `locales` and `defaultLocale` verbatim — which is why\n * substituting it (only when it is missing; see `routingAlias`) cannot change\n * the answer.\n */\nasync function readRouting(projectDir: string): Promise<NextI18n | null> {\n const path = firstExisting(projectDir, ROUTING_FILES)\n if (!path) return null\n\n const module = await executeConfig(path, { alias: routingAlias(path) })\n if (!module) return null\n\n // `export const routing = defineRouting(...)` is what the docs show, but a\n // default export is just as valid, and both may be present.\n for (const candidate of [module.routing, defaultExport(module)]) {\n const routing = asObject(candidate)\n if (!routing) continue\n\n const defaultLocale = asString(routing.defaultLocale)\n const locales = asStringArray(routing.locales)\n if (defaultLocale || locales) {\n return { ...(defaultLocale ? { defaultLocale } : {}), ...(locales ? { locales } : {}), source: path }\n }\n }\n\n return null\n}\n\n/**\n * Substitute `defineRouting` only when the real one cannot be found from the\n * routing file's own location.\n *\n * The real package always wins where it is installed — it is the authority on\n * its own API, and a substitution that silently shadowed it would be the kind\n * of quiet divergence this whole line of work is about. The stub is purely a\n * rescue for the case where the file exists and its dependencies do not, which\n * is a fresh clone, a CI job that skipped install, or a fixture. Reading a\n * declaration should not require a `node_modules` to be present.\n */\nfunction routingAlias(routingPath: string): Record<string, string> | undefined {\n if (resolvableFrom('next-intl/routing', routingPath)) return undefined\n\n const path = resolveStub('next-intl-routing')\n if (!path) return undefined\n\n log.debug(`next-intl is not installed for ${routingPath} — reading it with a stubbed defineRouting`)\n return { 'next-intl/routing': path }\n}\n\n/**\n * `next.config.js` may export `(phase, { defaultConfig }) => config`, sync or\n * async, which Next.js calls for you. An uncalled function is not a config, so\n * without this the `i18n` block of every project using that form is invisible.\n *\n * A function that throws yields nothing, like any other unreadable config.\n */\nasync function resolveConfigExport(exported: unknown, path: string): Promise<unknown> {\n if (typeof exported !== 'function') return exported\n\n try {\n return await (exported as (phase: string, context: unknown) => unknown)(\n 'phase-production-build',\n { defaultConfig: {} },\n )\n }\n catch (error) {\n log.warn(`Could not evaluate the config function in ${path}: ${toErrorMessage(error)}`)\n return undefined\n }\n}\n\nfunction resolvableFrom(specifier: string, fromFile: string): boolean {\n try {\n createRequire(fromFile).resolve(specifier)\n return true\n }\n catch {\n return false\n }\n}\n\n/** next-translate's `i18n.js`, a plain object of `{ locales, defaultLocale, pages }`. */\nasync function readNextTranslate(projectDir: string): Promise<NextI18n | null> {\n const path = firstExisting(projectDir, NEXT_TRANSLATE_FILES)\n if (!path) return null\n\n const module = await executeConfig(path)\n if (!module) return null\n\n const config = asObject(defaultExport(module))\n if (!config) return null\n\n const defaultLocale = asString(config.defaultLocale)\n const locales = asStringArray(config.locales)\n if (!defaultLocale && !locales) return null\n\n return { ...(defaultLocale ? { defaultLocale } : {}), ...(locales ? { locales } : {}), source: path }\n}\n\n/**\n * The Pages Router's `i18n` block. Read last because this is the file most\n * likely to throw: in a real project it is wrapped in `withNextIntl(...)`,\n * `withSentryConfig(...)` and whatever else, and needs their env to run.\n */\nasync function readNextConfig(projectDir: string): Promise<NextI18n | null> {\n const path = firstExisting(projectDir, NEXT_CONFIG_FILES)\n if (!path) return null\n\n const module = await executeConfig(path)\n if (!module) return null\n\n const config = asObject(await resolveConfigExport(defaultExport(module), path))\n const i18n = config && asObject(config.i18n)\n if (!i18n) return null\n\n const defaultLocale = asString(i18n.defaultLocale)\n const locales = asStringArray(i18n.locales)\n if (!defaultLocale && !locales) return null\n\n return { ...(defaultLocale ? { defaultLocale } : {}), ...(locales ? { locales } : {}), source: path }\n}\n","/**\n * Helpers for an adapter that resolves a project to a single locale directory.\n */\n\nimport { existsSync } from 'node:fs'\nimport { readFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport type { I18nConfig, LocaleDefinition, ProjectConfig } from '../config/types'\nimport { ConfigError } from '../utils/errors'\n\nconst NUXT_CONFIG_FILES = ['nuxt.config.ts', 'nuxt.config.js', 'nuxt.config.mjs']\n\nexport async function loadPackageJson(projectDir: string): Promise<Record<string, unknown> | null> {\n try {\n const raw = await readFile(join(projectDir, 'package.json'), 'utf-8')\n return JSON.parse(raw) as Record<string, unknown>\n }\n catch {\n return null\n }\n}\n\nexport function collectDependencies(pkg: Record<string, unknown>): Record<string, unknown> {\n return {\n ...(pkg.dependencies ?? {}) as Record<string, unknown>,\n ...(pkg.devDependencies ?? {}) as Record<string, unknown>,\n }\n}\n\nexport function hasNuxtConfig(dir: string): boolean {\n return NUXT_CONFIG_FILES.some(f => existsSync(join(dir, f)))\n}\n\nexport function noLocaleDirError(projectDir: string, searchedDirs: string[]): ConfigError {\n return new ConfigError(\n `No locale directory found in ${projectDir}. `\n + 'Looked in: ' + searchedDirs.join(', ') + '. '\n + 'Configure a .i18n-mcp.json with localeDirs for custom paths.',\n )\n}\n\n/** Build the I18nConfig for a project with a single locale directory ('root' layer). */\nexport function buildSingleDirConfig(opts: {\n projectDir: string\n localeDir: string\n defaultLocale: string\n locales: LocaleDefinition[]\n projectConfig: ProjectConfig | null\n}): I18nConfig {\n return {\n rootDir: opts.projectDir,\n defaultLocale: opts.defaultLocale,\n fallbackLocale: { default: [opts.defaultLocale] },\n locales: opts.locales,\n localeDirs: [{ path: opts.localeDir, layer: 'root', layerRootDir: opts.projectDir }],\n layerRootDirs: [opts.projectDir],\n projectConfig: opts.projectConfig ?? undefined,\n apps: [{ name: 'default', rootDir: opts.projectDir, layers: ['root'] }],\n }\n}\n","import { existsSync, statSync, readdirSync } from 'node:fs'\nimport { readdir, readFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport type { FrameworkAdapter, LocaleFileFormat } from '../types'\nimport type { I18nConfig, LocaleDefinition, ProjectConfig } from '../../config/types'\nimport { readNextI18n } from '../../config/framework/next'\nimport { applyLocaleOverride } from '../../config/locale-override'\nimport { ConfigError } from '../../utils/errors'\nimport { loadPackageJson, collectDependencies, hasNuxtConfig, noLocaleDirError, buildSingleDirConfig } from '../shared'\n\nconst COMMON_LOCALE_DIRS = [\n 'messages',\n 'public/locales',\n 'locales',\n 'src/i18n',\n 'src/locales',\n 'i18n',\n]\n\nconst NEXT_CONFIG_FILES = ['next.config.ts', 'next.config.js', 'next.config.mjs']\n\nconst NUXT_INDICATORS = ['@nuxt/kit', 'nuxt']\nconst VUE_INDICATORS = ['vue']\n\nconst I18N_DEPS = ['next-intl', 'next-translate', 'next-i18next', 'react-i18next', 'react-intl']\n\nconst SKIP_DIRS = new Set(['node_modules', '.git', '.DS_Store'])\n\nexport class ReactAdapter implements FrameworkAdapter {\n readonly name = 'react'\n readonly label = 'React / Next.js'\n readonly localeFileFormat: LocaleFileFormat = 'json'\n\n async detect(projectDir: string): Promise<number> {\n const pkg = await loadPackageJson(projectDir)\n if (!pkg) return 0\n\n const allDeps = collectDependencies(pkg)\n if (isConflictingFramework(projectDir, allDeps)) return 0\n\n const isNext = 'next' in allDeps\n const isReact = 'react' in allDeps && 'react-dom' in allDeps\n\n if (!isNext && !isReact) return 0\n\n return computeScore(projectDir, allDeps, isNext)\n }\n\n async resolve(projectDir: string, projectConfig: ProjectConfig | null): Promise<I18nConfig> {\n const localeDir = await findLocaleDir(projectDir)\n if (!localeDir) {\n throw noLocaleDirError(projectDir, COMMON_LOCALE_DIRS)\n }\n\n const locales = await discoverLocales(localeDir)\n const [firstLocale] = locales\n if (firstLocale === undefined) {\n throw new ConfigError(\n `No locale files found in ${localeDir}. `\n + 'Make sure your React/Next.js project has locale directories like messages/en/ or locale JSON files.',\n )\n }\n\n // Declared first, then what the project already tells next-intl or Next\n // itself, and only then directory order — which is not a statement about\n // the default locale at all, merely the alphabet (#296).\n const framework = await readNextI18n(projectDir)\n const defaultLocale = projectConfig?.defaultLocale ?? framework?.defaultLocale ?? firstLocale.code\n\n return buildSingleDirConfig({\n projectDir,\n localeDir,\n defaultLocale,\n locales: applyLocaleOverride(locales, projectConfig?.locales),\n projectConfig,\n })\n }\n}\n\n// ─── Detection helpers ──────────────────────────────────────────\n\nfunction isConflictingFramework(projectDir: string, deps: Record<string, unknown>): boolean {\n for (const indicator of NUXT_INDICATORS) {\n if (indicator in deps) return true\n }\n for (const indicator of VUE_INDICATORS) {\n if (indicator in deps) return true\n }\n return hasNuxtConfig(projectDir)\n}\n\nfunction hasNextConfig(projectDir: string): boolean {\n return NEXT_CONFIG_FILES.some(f => existsSync(join(projectDir, f)))\n}\n\nasync function computeScore(\n projectDir: string,\n deps: Record<string, unknown>,\n isNext: boolean,\n): Promise<number> {\n let score = isNext ? 5 : 3\n\n if (I18N_DEPS.some(dep => dep in deps)) score += 2\n\n if (isNext && hasNextConfig(projectDir)) score += 1\n\n try {\n const localeDir = findLocaleDirSync(projectDir)\n if (localeDir) {\n const entries = readdirSync(localeDir)\n if (entries.some(e => isLocaleContent(join(localeDir, e)))) score += 2\n }\n }\n catch {\n // Can't read dirs — skip bonus\n }\n\n return score\n}\n\n// ─── Resolution helpers ─────────────────────────────────────────\n\nasync function findLocaleDir(projectDir: string): Promise<string | null> {\n const fromConfig = await tryNextConfig(projectDir)\n if (fromConfig) return fromConfig\n\n return findLocaleDirSync(projectDir)\n}\n\nfunction findLocaleDirSync(projectDir: string): string | null {\n for (const dir of COMMON_LOCALE_DIRS) {\n const fullPath = join(projectDir, dir)\n if (existsSync(fullPath)) return fullPath\n }\n return null\n}\n\nfunction isLocaleContent(path: string): boolean {\n if (path.endsWith('.json')) return true\n return isLocaleSubdir(path)\n}\n\nfunction isLocaleSubdir(path: string): boolean {\n if (!existsSync(path)) return false\n try {\n if (!statSync(path).isDirectory()) return false\n const files = readdirSync(path)\n return files.some(f => f.endsWith('.json'))\n }\n catch {\n return false\n }\n}\n\nasync function tryNextConfig(projectDir: string): Promise<string | null> {\n for (const file of NEXT_CONFIG_FILES) {\n const fullPath = join(projectDir, file)\n if (!existsSync(fullPath)) continue\n\n const result = await tryExtractFromNextConfig(projectDir, fullPath)\n if (result) return result\n }\n\n return null\n}\n\nasync function tryExtractFromNextConfig(\n projectDir: string,\n configPath: string,\n): Promise<string | null> {\n try {\n const content = await readFile(configPath, 'utf-8')\n\n if (/createNextIntlPlugin/.test(content) && existsSync(join(projectDir, 'messages'))) {\n return join(projectDir, 'messages')\n }\n\n if (/next-translate/.test(content) && existsSync(join(projectDir, 'locales'))) {\n return join(projectDir, 'locales')\n }\n\n return tryExtractPathFromConfig(projectDir, content)\n }\n catch {\n return null\n }\n}\n\nfunction tryExtractPathFromConfig(projectDir: string, content: string): string | null {\n const pathMatch = content.match(/(?:messages|localeDir|locales)\\s*:\\s*['\"]([^'\"]+)/)\n const rawPath = pathMatch?.[1]\n if (!rawPath) return null\n\n const path = rawPath.replace(/\\/\\*\\/\\*$/, '').replace(/\\/\\*$/, '')\n return existsSync(join(projectDir, path)) ? join(projectDir, path) : null\n}\n\nasync function discoverLocales(localeDir: string): Promise<LocaleDefinition[]> {\n let entries: string[]\n try {\n entries = await readdir(localeDir)\n }\n catch {\n return []\n }\n\n const localeCodes = new Set<string>()\n\n // Namespaced layout: messages/en/common.json\n for (const entry of entries) {\n if (SKIP_DIRS.has(entry) || entry.startsWith('.')) continue\n const fullPath = join(localeDir, entry)\n if (isLocaleSubdir(fullPath)) localeCodes.add(entry)\n }\n\n if (localeCodes.size > 0) {\n return [...localeCodes].sort().map(code => ({\n code,\n language: code,\n }))\n }\n\n // Flat JSON layout: locales/en.json — `file` is required here, otherwise\n // resolveLocaleEntries cannot resolve flat entries and every read/write\n // becomes a silent no-op (#194).\n return entries\n .filter(entry => entry.endsWith('.json'))\n .sort()\n .map(file => ({\n code: file.replace(/\\.json$/, ''),\n language: file.replace(/\\.json$/, ''),\n file,\n }))\n}\n","/**\n * Everything the process remembers about a project it has already read.\n *\n * One owner, because there is one moment that has to forget all of it: a\n * long-running MCP server clears the cache after the user edits a config file,\n * and any memo keeping its own copy would survive that and keep answering with\n * the project as it was.\n */\nimport type { I18nConfig } from './types.js'\nimport { log } from '../utils/logger.js'\n\nconst configs = new Map<string, I18nConfig>()\n\nlet lastConfig: I18nConfig | null = null\n\n/** The resolved config for a canonical project directory, if one is cached. */\nexport function getCachedConfigFor(canonicalDir: string): I18nConfig | undefined {\n return configs.get(canonicalDir)\n}\n\nexport function cacheConfig(canonicalDir: string, config: I18nConfig): void {\n configs.set(canonicalDir, config)\n lastConfig = config\n}\n\n/** The most recently resolved config, or null when nothing has been resolved. */\nexport function getCachedConfig(): I18nConfig | null {\n return lastConfig\n}\n\nexport function clearConfigCache(): void {\n configs.clear()\n lastConfig = null\n log.debug('Config cache cleared')\n}\n","/**\n * Consumer-graph inference from the package manager workspace.\n *\n * Everything the kit does across layers — app-scoped orphan evidence,\n * misplaced usages, unconsumed layers — runs on `config.apps`: which app can\n * render which layer's keys. Only the Nuxt adapter can answer that from\n * framework knowledge, because a Nuxt `extends` chain *is* a consumer graph.\n * For every other stack the same answer is already written down in the\n * workspace: a package that contains a locale dir owns that layer, and a\n * `package.json` dependency edge from one such package to another is a\n * consumption edge.\n *\n * ## What counts as an app\n *\n * An app is a layer-owning workspace package that no *other* layer-owning\n * package depends on, directly or transitively — the roots of the\n * layer-owning subgraph. A package something else depends on (a UI kit, a\n * shared locale package) is not an app of its own: its keys are rendered by\n * its dependents, and calling it an app would tell the orphan scan that its\n * own directory is a place where its keys may legitimately be used, which is\n * evidence the scan must never invent. When every layer-owning package is\n * depended on by another one — a dependency cycle, which package managers\n * permit — there is no root to pick, and then every layer-owning package\n * becomes an app: a graph wider than the truth, never narrower, and narrower\n * is the direction that deletes keys. Each app consumes its own layers plus\n * the layers of its transitive dependencies. Layers that lie outside every\n * workspace package are attached to every app, so an unclaimed locale dir\n * keeps behaving exactly as it does without inference.\n *\n * Inference is refused (`null`) when the project is not a workspace, when no\n * package owns a layer, or when fewer than two apps come out of it — the\n * single-app fallback the adapters build is already correct for those, and\n * replacing it would change names for no gain.\n */\n\nimport { readFile } from 'node:fs/promises'\nimport { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path'\nimport { glob } from 'tinyglobby'\nimport type { AppInfo, LocaleDir } from './types.js'\nimport { log } from '../utils/logger.js'\n\n/** A package in the workspace, with its edges to other workspace packages. */\nexport interface WorkspacePackage {\n /** Absolute path to the directory holding the package.json. */\n dir: string\n /** `name` from the manifest, or the directory name when it declares none. */\n name: string\n /** Names of other workspace packages this one depends on (direct edges). */\n deps: string[]\n}\n\nconst DEPENDENCY_FIELDS = ['dependencies', 'devDependencies', 'peerDependencies'] as const\n\n/**\n * Derive the consumer graph for `layers` from the workspace `projectDir` is\n * the root of. Returns null when the workspace cannot answer the question —\n * see the module header for which cases those are and why.\n */\nexport async function inferWorkspaceApps(\n projectDir: string,\n layers: LocaleDir[],\n): Promise<AppInfo[] | null> {\n const workspace = await readWorkspacePatterns(projectDir)\n if (!workspace) return null\n\n const packages = await readWorkspacePackages(projectDir, workspace.patterns)\n if (packages.length === 0) return null\n\n log.debug(\n `Workspace consumer graph: ${packages.length} package(s) from ${workspace.source} `\n + `(${workspace.patterns.join(', ')})`,\n )\n\n return buildWorkspaceApps(packages, layers)\n}\n\n/**\n * The inference itself, over already-read workspace packages: ownership by\n * directory containment, consumption by dependency edges.\n */\nexport function buildWorkspaceApps(\n packages: WorkspacePackage[],\n layers: LocaleDir[],\n): AppInfo[] | null {\n const byName = new Map(packages.map(pkg => [pkg.name, pkg]))\n\n // Alias entries are skipped: their locale dir belongs to the layer they\n // point at, so owning them by path would credit the wrong package.\n const canonical = layers.filter(layer => !layer.aliasOf)\n\n const ownedBy = new Map<string, string[]>()\n const unowned: string[] = []\n for (const layer of canonical) {\n const owner = ownerOfDir(packages, layer.path)\n if (!owner) {\n unowned.push(layer.layer)\n continue\n }\n const owned = ownedBy.get(owner.name) ?? []\n owned.push(layer.layer)\n ownedBy.set(owner.name, owned)\n }\n\n if (ownedBy.size === 0) return null\n\n const closure = transitiveClosure(byName)\n\n const depended = new Set<string>()\n for (const name of ownedBy.keys()) {\n for (const dep of closure.get(name) ?? []) {\n if (dep !== name && ownedBy.has(dep)) depended.add(dep)\n }\n }\n\n const roots = [...ownedBy.keys()].filter(name => !depended.has(name))\n const appNames = (roots.length > 0 ? roots : [...ownedBy.keys()]).sort()\n if (appNames.length < 2) return null\n\n return appNames.map((name) => {\n const consumed = new Set(ownedBy.get(name) ?? [])\n for (const dep of closure.get(name) ?? []) {\n for (const layer of ownedBy.get(dep) ?? []) consumed.add(layer)\n }\n for (const layer of unowned) consumed.add(layer)\n\n return {\n name,\n rootDir: byName.get(name)!.dir,\n // Reported in the config's own layer order, so two runs agree.\n layers: canonical.filter(layer => consumed.has(layer.layer)).map(layer => layer.layer),\n source: 'workspace' as const,\n }\n })\n}\n\n// ─── Workspace discovery ────────────────────────────────────────\n\n/**\n * The package globs of the workspace rooted at `projectDir`, from whichever\n * package manager declares one. Only `projectDir` itself is inspected: a\n * project detected from inside one workspace package is that package's\n * project, and reading the enclosing workspace would widen the graph past\n * what the caller asked about.\n */\nasync function readWorkspacePatterns(\n projectDir: string,\n): Promise<{ patterns: string[]; source: string } | null> {\n for (const file of ['pnpm-workspace.yaml', 'pnpm-workspace.yml']) {\n const raw = await readFileOrNull(join(projectDir, file))\n if (raw === null) continue\n const patterns = parsePnpmWorkspacePackages(raw)\n if (patterns.length > 0) return { patterns, source: file }\n }\n\n const manifest = await readJsonOrNull(join(projectDir, 'package.json'))\n const patterns = manifest ? workspacesField(manifest) : []\n return patterns.length > 0 ? { patterns, source: 'package.json' } : null\n}\n\n/**\n * The `packages:` sequence of a `pnpm-workspace.yaml`, in block or flow form.\n *\n * A hand-rolled reader rather than a YAML parser: the file's other keys are\n * none of our business, one list of strings is the whole contract, and a\n * parser dependency for it would ship in every install.\n */\nexport function parsePnpmWorkspacePackages(yamlText: string): string[] {\n const patterns: string[] = []\n let inBlock = false\n\n for (const line of yamlText.split(/\\r?\\n/)) {\n if (!inBlock) {\n const header = /^packages:\\s*(.*)$/.exec(line)\n if (!header) continue\n const inline = header[1]!.trim()\n if (inline.startsWith('[')) {\n const end = inline.lastIndexOf(']')\n return inline.slice(1, end === -1 ? inline.length : end)\n .split(',')\n .map(item => unquote(item.trim()))\n .filter(item => item.length > 0)\n }\n inBlock = true\n continue\n }\n\n const trimmed = line.trim()\n if (trimmed === '' || trimmed.startsWith('#')) continue\n const item = /^-\\s*(.+)$/.exec(trimmed)\n // Anything that is not a sequence entry ends the block — the next key.\n if (!item) break\n const value = unquote(item[1]!.trim())\n if (value.length > 0) patterns.push(value)\n }\n\n return patterns\n}\n\n/** The npm/yarn `workspaces` field, in both of its accepted spellings. */\nfunction workspacesField(manifest: Record<string, unknown>): string[] {\n const field = manifest.workspaces\n if (Array.isArray(field)) return field.filter((p): p is string => typeof p === 'string')\n if (field && typeof field === 'object') {\n const nested = (field as { packages?: unknown }).packages\n if (Array.isArray(nested)) return nested.filter((p): p is string => typeof p === 'string')\n }\n return []\n}\n\n/** Expand the workspace globs to the packages they name. */\nasync function readWorkspacePackages(\n projectDir: string,\n patterns: string[],\n): Promise<WorkspacePackage[]> {\n const include = patterns.filter(p => !p.startsWith('!'))\n const exclude = patterns.filter(p => p.startsWith('!')).map(p => p.slice(1))\n if (include.length === 0) return []\n\n let manifests: string[]\n try {\n manifests = await glob(include.map(toManifestPattern), {\n cwd: projectDir,\n absolute: true,\n // Installed copies of a workspace package are not the package.\n ignore: ['**/node_modules/**', ...exclude.map(toManifestPattern)],\n })\n }\n catch (error) {\n log.debug(`Workspace consumer graph: glob failed (${String(error)})`)\n return []\n }\n\n const packages: WorkspacePackage[] = []\n for (const manifest of manifests) {\n const pkg = await readJsonOrNull(manifest)\n if (!pkg) continue\n const dir = dirname(resolve(manifest))\n const declared = typeof pkg.name === 'string' ? pkg.name.trim() : ''\n packages.push({\n dir,\n name: declared.length > 0 ? declared : basename(dir),\n deps: dependencyNames(pkg),\n })\n }\n\n // Edges to packages outside the workspace say nothing about layers.\n const names = new Set(packages.map(pkg => pkg.name))\n return packages.map(pkg => ({\n ...pkg,\n deps: pkg.deps.filter(dep => dep !== pkg.name && names.has(dep)),\n }))\n}\n\n/**\n * A workspace glob names directories; matching their manifests instead keeps\n * directories that are not packages (a `packages/*` that also holds docs) out\n * of the graph.\n */\nfunction toManifestPattern(pattern: string): string {\n const trimmed = pattern.replace(/\\/+$/, '')\n if (trimmed === '' || trimmed === '.') return 'package.json'\n return `${trimmed}/package.json`\n}\n\n/**\n * Dependency names across every field that can carry a workspace edge. The\n * version range is irrelevant — `workspace:*`, a published range, or a file\n * link all mean the same thing once the name matches a workspace package.\n */\nfunction dependencyNames(manifest: Record<string, unknown>): string[] {\n const names: string[] = []\n for (const field of DEPENDENCY_FIELDS) {\n const deps = manifest[field]\n if (deps && typeof deps === 'object') names.push(...Object.keys(deps))\n }\n return names\n}\n\n// ─── Graph helpers ──────────────────────────────────────────────\n\n/** The innermost workspace package containing `dir`, if any. */\nfunction ownerOfDir(packages: WorkspacePackage[], dir: string): WorkspacePackage | undefined {\n let best: WorkspacePackage | undefined\n for (const pkg of packages) {\n if (!isWithin(dir, pkg.dir)) continue\n if (!best || pkg.dir.length > best.dir.length) best = pkg\n }\n return best\n}\n\n/** True when `child` equals `parent` or lies inside it. */\nfunction isWithin(child: string, parent: string): boolean {\n const rel = relative(parent, resolve(child))\n return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel))\n}\n\n/** Package name → every workspace package reachable from it. Cycle-safe. */\nfunction transitiveClosure(byName: Map<string, WorkspacePackage>): Map<string, Set<string>> {\n const closure = new Map<string, Set<string>>()\n\n for (const [name, pkg] of byName) {\n const reachable = new Set<string>()\n const stack = [...pkg.deps]\n while (stack.length > 0) {\n const next = stack.pop()!\n if (reachable.has(next)) continue\n const dep = byName.get(next)\n if (!dep) continue\n reachable.add(next)\n stack.push(...dep.deps)\n }\n closure.set(name, reachable)\n }\n\n return closure\n}\n\n// ─── File reading ───────────────────────────────────────────────\n\nasync function readFileOrNull(path: string): Promise<string | null> {\n try {\n return await readFile(path, 'utf-8')\n }\n catch {\n return null\n }\n}\n\nasync function readJsonOrNull(path: string): Promise<Record<string, unknown> | null> {\n const raw = await readFileOrNull(path)\n if (raw === null) return null\n try {\n const parsed: unknown = JSON.parse(raw)\n return parsed && typeof parsed === 'object' ? parsed as Record<string, unknown> : null\n }\n catch {\n log.debug(`Workspace consumer graph: ignoring unparseable ${path}`)\n return null\n }\n}\n\n/** Strip YAML quoting and any trailing comment from a sequence entry. */\nfunction unquote(value: string): string {\n const quoted = /^(['\"])(.*?)\\1/.exec(value)\n if (quoted) return quoted[2]!\n const hash = value.indexOf(' #')\n return (hash === -1 ? value : value.slice(0, hash)).trim()\n}\n","import type { AppInfo, I18nConfig, ProjectConfig } from './types'\nimport { registerAdapter, detectFramework } from '../adapters/registry'\nimport { NuxtAdapter } from '../adapters/nuxt/index'\nimport { LaravelAdapter } from '../adapters/laravel/index'\nimport { GenericAdapter } from '../adapters/generic/index'\nimport { ReactAdapter } from '../adapters/react/index'\nimport { loadProjectConfig } from './project-config'\nimport { log } from '../utils/logger'\nimport { canonicalPath } from './paths'\nimport { cacheConfig, getCachedConfigFor } from './cache'\nimport { inferWorkspaceApps } from './workspace-graph'\n\n// Discovery moved to the Nuxt adapter, where the rest of the Nuxt knowledge\n// lives; re-exported here because this is where callers import it from.\nexport { discoverNuxtApps } from '../adapters/nuxt/discovery'\n\n// The cache itself lives in ./cache, which owns every memo that has to be\n// forgotten together. Re-exported here because this has been its import path\n// since before there was more than one thing to clear.\nexport { clearConfigCache, getCachedConfig } from './cache'\n\nregisterAdapter(new NuxtAdapter())\nregisterAdapter(new LaravelAdapter())\nregisterAdapter(new GenericAdapter())\nregisterAdapter(new ReactAdapter())\n\nexport async function detectI18nConfig(projectDir: string): Promise<I18nConfig> {\n const canonDir = canonicalPath(projectDir)\n const cached = getCachedConfigFor(canonDir)\n if (cached) {\n log.debug('Using cached i18n config')\n return cached\n }\n\n log.info(`Detecting i18n config from: ${projectDir}`)\n\n // Read once for the whole detection and handed to the adapter, which is what\n // makes the deprecated-key warning fire once rather than once per app.\n const projectConfig = await loadProjectConfig(projectDir)\n const hint = projectConfig?.framework\n\n const adapter = await detectFramework(projectDir, hint)\n log.info(`Detected framework: ${adapter.label}`)\n\n const config = await adapter.resolve(projectDir, projectConfig)\n config.framework = adapter.name\n await applyConsumerGraph(config, projectConfig, projectDir)\n cacheConfig(canonDir, config)\n\n log.info(`Detected ${config.locales.length} locales, ${config.localeDirs.length} locale directories`)\n return config\n}\n\n/**\n * Settle the consumer graph in `config.apps`, which every cross-layer\n * operation reads, once the adapter has had its say.\n *\n * A declared `apps` list wins outright: it is the only way to correct a graph\n * the tool got wrong, so nothing may override it. Otherwise an adapter that\n * discovered real apps (Nuxt, from its `extends` chain) is left alone, and\n * only the single placeholder app the other adapters emit is open to being\n * replaced by what the workspace says. This lives here rather than in an\n * adapter because it is framework-independent: locale dirs plus package\n * manifests, which every adapter has already produced by this point.\n */\nasync function applyConsumerGraph(\n config: I18nConfig,\n projectConfig: ProjectConfig | null,\n projectDir: string,\n): Promise<void> {\n const declared = projectConfig?.apps\n if (declared && declared.length > 0) {\n config.apps = declared.map(app => declaredApp(app, config))\n warnUnknownDeclaredLayers(config)\n log.debug(`Consumer graph declared in the project config: ${describeApps(config.apps)}`)\n return\n }\n\n if (projectConfig?.consumerGraph === 'off') return\n\n const placeholder = config.apps.length === 1 && config.apps[0]?.name === 'default'\n if (!placeholder) return\n\n const inferred = await inferWorkspaceApps(projectDir, config.localeDirs)\n if (!inferred) return\n\n config.apps = inferred\n log.debug(`Consumer graph inferred from the workspace: ${describeApps(inferred)}`)\n}\n\n/**\n * A declared app carries no directory, and the orphan scan needs one to know\n * which source tree is that app's. The first of its layers that has a locale\n * dir supplies it — by convention an app lists its own layer first, and the\n * shared layers it consumes after — falling back to the project root, which\n * scopes nothing away.\n */\nfunction declaredApp(app: { name: string, layers: string[] }, config: I18nConfig): AppInfo {\n const own = app.layers\n .map(layer => config.localeDirs.find(dir => dir.layer === layer))\n .find(dir => dir !== undefined)\n\n return {\n name: app.name,\n rootDir: own?.layerRootDir ?? config.rootDir,\n layers: [...app.layers],\n source: 'declared',\n }\n}\n\n/**\n * A declared layer name that matches no locale dir is a typo rather than a\n * layer, and it silently contributes nothing to the graph — so say so.\n */\nfunction warnUnknownDeclaredLayers(config: I18nConfig): void {\n const known = new Set(config.localeDirs.map(dir => dir.layer))\n const unknown = [...new Set(config.apps.flatMap(app => app.layers))].filter(layer => !known.has(layer))\n if (unknown.length === 0) return\n\n log.warn(\n `Declared apps reference unknown layer(s): ${unknown.join(', ')}. `\n + `Detected layers: ${[...known].join(', ')}.`,\n )\n}\n\nfunction describeApps(apps: AppInfo[]): string {\n return apps.map(app => `${app.name} -> [${app.layers.join(', ')}]`).join('; ')\n}\n"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import "./project-config-eLR0J377.js";
2
+ import "./json-writer-ek8yEI5R.js";
3
+ import "./php-reader-DRpcRVzv.js";
4
+ import { i as discoverNuxtApps, n as clearConfigCache, r as getCachedConfig, t as detectI18nConfig } from "./detector-B4z_RZde.js";
5
+ export { clearConfigCache, detectI18nConfig, discoverNuxtApps, getCachedConfig };